Refileの導入
ここからは、Refileを使った実装例を紹介します。なお、紹介済みの手順でCarrierWaveの実装を行った後に以下の手順を試す場合は、いったん適用したマイグレーションをロールバックしておく必要があります。
bin/rails db:rollback
インストール
GemfileにRefileを追記します。
…(中略)… gem 'refile', github: 'refile/refile', require: 'refile/rails' …(中略)…
このように、Rails 5.2では、GitHub上の最新のmasterブランチを使わないとエラーが発生します。rackの依存関係の問題で、古いバージョン(0.3.0)のRefileが入ってしまうことが原因です。このあたりは初心者にとってつまずきやすいポイントですが、公式のREADMEにも執筆時点では記載がなかったので注意が必要です。
以下のコマンドを実行しRefileをインストールします。
bin/bundle
執筆時点では、0.6.2がインストールされますが、Gemfileにバージョン指定すると依存関係が解決できずエラーとなるので「github: 'refile/refile'」と明示的に指定する必要があります。
マイグレーション
articlesテーブルにアップロードするファイル関連用のカラムを追加するマイグレーションファイルを追加します。
bin/rails g migration add_image_to_articles image_id:string image_filename:string image_size:string image_content_type:string
追加したカラムのprefixである「image」はすべて共通の名称である点に注意が必要です。
追加する各カラムの用途は以下の通りです。
カラム名 | 用途 |
---|---|
image_id | ファイル固有のキー |
image_filename | アップロード時のファイル名 |
image_size | アップロード時のファイルサイズ |
image_content_type | アップロードされたファイルのContent-Type |
なお、少し気をつける必要がある点があります。執筆時点の公式READMEに従うと、ファイルサイズを保存するカラム名は「image_content_size」なのですが、これだと意図するように動いてくれません。実際にはcontentが不要で「image_size」とすると正常に動作します。
生成されたマイグレーションファイルは以下の通りです。
class AddImageToArticles < ActiveRecord::Migration[5.2] def change add_column :articles, :image_id, :string add_column :articles, :image_filename, :string add_column :articles, :image_size, :string add_column :articles, :image_content_type, :string end end
以下のコマンドを実行してマイグレーションを適用します。
bin/rails db:migrate
モデルの修正
CarrierWaveと違い、Refileではアップローダー用のクラスはありません。モデルにattachmentというDSLでファイルアップロード用の名称(ここではimage)をシンボルで指定するだけで済みます。
class Article < ApplicationRecord attachment :image …(中略)…
ビューファイルの修正
まず、フォームに画像パス用のフィールドを追加します。以下のように修正します。
…(中略)… <div class="field"> <%= form.label :image %> <%= form.attachment_field :image %> </div> …(中略)…
attachment_fieldは、Refileが提供するヘルパーメソッドです。引数にモデルで指定したattachmentの引数と同じ値(ここでは:image)を指定します。
次に、アップロードした画像ファイルを表示するため、以下のように追加します。
…(中略)… <p> <strong>Image:</strong> <% if @article.image %> <%= image_tag attachment_url(@article, :image) %> <% end %> </p> …(中略)…
attachment_urlヘルパーメソッドはRefileが提供するメソッドで、第1引数にモデルのインスタンスを指定し、第2引数にモデルで指定したattachmentの引数(ここでは:image)を指定します。attachment_urlはファイルアップロードされていない場合、例外が発生するので、上記のように@article.imageの存在チェックを入れる必要があります。
コントローラーの修正
CarrierWave同様、Strong Parameters用の修正を行います。
…(中略)… def article_params params.require(:article).permit(:title, :body, :image) end …(中略)…
シークレットキーの追加
最後に、Refile用のシークレットキーを設定ファイルに記述します。設定するシークレットキーは任意で構いません。
ruby -r securerandom -e 'p SecureRandom.hex(64)'
を実行して得られた値をセットしておきましょう。production環境では環境変数にするなど配慮が必要です。
Refile.secret_key = '[SecureRandom.hex(64)の実行結果]'
動作確認
CarrierWave同様、rails sコマンドでpumaサーバーを起動し、任意の記事を編集して画像がアップロードできることが確認できます。
なお、Refileではアップロード後のファイルは、tmp/uploads/store/ディレクトリ配下にimage_idに入っているファイル固有のキーと、一致するファイル名で保持されます。
まとめ
ここまで、ファイルアップローダーの主なgemのうち、CarrierWave/Refileを紹介しました。
次回は、Shrineを紹介するとともに、Rails5.2から導入されたActiveStorageについても紹介する予定です。