カテゴリー: BackEnd

Shrineを使って画像をアップロードする

はじめに

こんにちは、onoです。

以前、CarrierWaveを使って画像をアップロードするフォームを作成しました。

CarrierWaveは多機能で使いやすいGemだと思いますが、コードが大きく複雑なため、一般的な使い方から外れた場合や問題が発生した場合に処理を追っていくのが大変です。

そこで、今回は実装がシンプルで必要な機能を選んで追加できるShrineを使ってみます。

Shrineとは

簡単な説明

Shrineはファイルをアタッチするためのツールです。
主に画像をアップロードする際に利用されるのではないかと思います。

作者

ShrineはJanko Marohnić氏(リポジトリはこちら)が2015年9月から開発しています。

特徴

主な特徴としては下記の2つが挙げられます。

  • Shrine本体は必要最小限の機能のみを実装しているため、シンプルでコードが小さい。
  • リサイズやダイレクトアップロードなど、必要な機能のみをプラグインで追加できる。

 

下準備

Gemを追加

プロジェクトを作成後、Gemfileに下記のGemを追加します。

gem 'shrine'

 

初期設定

画像をアップロードするディレクトリの指定と使用するプラグインを宣言します。
アプリケーション全体で共通の設定は、config/initializers/で行います。

require "shrine"
require "shrine/storage/file_system"

# アップロードするディレクトリの指定
Shrine.storages = {
    cache: Shrine::Storage::FileSystem.new("public", prefix: "uploads/cache"), # temporary
    store: Shrine::Storage::FileSystem.new("public", prefix: "uploads/store"), # permanent
}

# 使用するプラグインの宣言
Shrine.plugin :activerecord
Shrine.plugin :cached_attachment_data # for forms

 

テーブルを作成する

アップロードした画像を管理するテーブルを作成します。
アップロードした画像の情報を保存するカラムはtext型の「xxx_data」という名前にします(xxxはモデルの中でアップローダをアタッチする際に指定するシンボル名)

class CreatePhotos < ActiveRecord::Migration[5.0]
  def change
    create_table :photos do |t|
      t.string   :name,  limit: 16,  null: false
      t.text     :image_data,  comment: '「アップローダに渡すシンボル名_data」とい名前にする'

      t.timestamps
    end
  end
end

 

実装

Uploaderの実装

モデルにアタッチするアップローダを実装します。
特にディレクトリに指定はありませんが、app/uploaders/に追加していきます。

class ImageUploader < Shrine
end

 

Modelの実装

実装したアップローダをアタッチします。

class Photo < ApplicationRecord
  include ImageUploader[:image]

  validates :name,  presence: true, length: { maximum: 16 }
end

 

Controllerの実装

下記の通り、scaffoldで生成したコードの一部を修正します。

def photo_params
  # before
  params.require(:photo).permit(:name, :image_data)

  # after
  params.require(:photo).permit(:name, :image)
end

 

Viewの実装

画像をアップロードするフォームを実装します。
アップロードした画像のアドレスはxxx_urlで取得できます(xxxはモデルの中でアップローダをアタッチする際に指定するシンボル名)

<%= form_for(photo) do |f| %>
    <!--省略-->
    <div class="field">
      <%= f.label :name %>
      <%= f.text_field :name %>
    </div>
    <div class="field">
      <%= f.label :image_data %>
      <% if photo.cached_image_data.present? %>
          <!--バリデーションに失敗した場合、ここで画像を表示する-->
          <%= image_tag photo.image_url %>
      <% end %>
      <%= f.hidden_field :image, value: photo.cached_image_data %>
      <%= f.file_field :image %>
    </div>
    <div class="actions">
      <%= f.submit %>
    </div>
<% end %>

 

インサートされるレコード

フォームから画像をアップロードして保存すると、下記のようなレコードがインサートされます。

mysql> select * from photos;
+----+------------------------------------------------------------------------------------------------------------------------------------------------+---------------------+---------------------+
| id | image_data                                                                                                                                     | created_at          | updated_at          |
+----+------------------------------------------------------------------------------------------------------------------------------------------------+---------------------+---------------------+
|  4 | {"id":"01ebba4bae62c5fb1ecd136224f9d1dd.jpg","storage":"store","metadata":{"filename":"1182774.rsz.jpg","size":2989,"mime_type":"image/jpeg"}} | 2017-04-16 11:41:19 | 2017-04-16 11:41:19 |
+----+------------------------------------------------------------------------------------------------------------------------------------------------+---------------------+---------------------+
1 row in set (0.00 sec)

 

さいごに

今後はプラグインを追加して、ファイル名の変更、リサイズ、サムネイルの作成などを行なっていきます。

Hiroki Ono

シェア
執筆者:
Hiroki Ono

最近の投稿

フロントエンドで動画デコレーション&レンダリング

はじめに 今回は、以下のように…

3週間 前

Goのクエリビルダー goqu を使ってみる

はじめに 最近携わっているとあ…

1か月 前

【Xcode15】プライバシーマニフェスト対応に備えて

はじめに こんにちは、suzu…

2か月 前

FSMを使った状態管理をGoで実装する

はじめに 一般的なアプリケーシ…

3か月 前