Railsのフォームにファイルアップロードを付けるときに便利なのがrefileです。ファイルアップロード系のgemといえばcarrierwaveが広く知られていますが、refileはcarrierwaveの作者がその後継として作ったもので比較的新しいものです。refileの特徴には
- ファイルのアップロード先をファイルシステム・S3など設定できる
- 簡単にORMに組み込める
- 画像のサムネイルを生成できる
があります。ここではrefileを使ったファイルアップロードの実装手順を紹介します。
作ってみるもの
今回はシンプルに画像がアップロード出来るだけのフォームを実装していきます。
ここで作成した成果物のコードはGitHubで公開しています。
refileのインストール
Gemfileに追加します:
Gemfile
gem "refile", require: "refile/rails"
gem "refile-mini_magick"
追加したらインストールしRailsサーバを再起動します。
bundle
Imagemagickをインストールします:
brew install imagemagick # OS X
sudo apt-get install imagemagick # Ubuntu
ファイルアップロードを実装する
まずPhoto
モデルを作ります。ファイルを持つモデルにはファイル名を格納するカラムが1つ必要です。そのカラムは_id
で終わらないといけない命名規則があります。ここではfile_id
とします。
rails generate scaffold Photo name:string file_id:string
file_id
カラムにユニーク制約を付けるためにマイグレーションファイルを修正します:
db/migrate/20160911080000_create_photos.rb
class CreatePhotos < ActiveRecord::Migration
def change
create_table :photos do |t|
t.string :name, null: false
t.string :file_id, null: false
t.timestamps null: false
end
add_index :photos, :file_id, unique: true
end
end
データベースにマイグレーションをかけます:
rake db:migrate
次にattachment
メソッドをPhoto
モデルに追加します。ここではファイルアップロードを必須にしたいのでvalidates_presence_of :file
をつけていますが、必須にする必要がなければこれを省いて下さい。
app/models/photo.rb
class Photo < ActiveRecord::Base
validates_presence_of :name
attachment :file
validates_presence_of :file
end
PhotosControllerのstrong parametersにfile
を追加します:
app/controllers/photos_controller.rb
class PhotosController < ApplicationController
# ...
def photo_params
params.require(:photo).permit(:name, :file)
end
end
ビューで画像を表示する箇所にattachment_image_tag
を埋め込みます:
app/views/photos/index.html.erb
...
<% @photos.each do |photo| %>
<tr>
<td><%= photo.name %></td>
<td><%= attachment_image_tag photo, :file, :fill, 100, 100, format: 'jpeg' %></td>
<td><%= link_to 'Show', photo %></td>
<td><%= link_to 'Edit', edit_photo_path(photo) %></td>
<td><%= link_to 'Destroy', photo, method: :delete, data: { confirm: 'Are you sure?' } %></td>
</tr>
<% end %>
...
app/views/photos/show.html.erb
<p id="notice"><%= notice %></p>
<p>
<strong>Name:</strong>
<%= @photo.name %>
</p>
<p>
<strong>File:</strong>
<%= attachment_image_tag @photo, :file, :fill, 300, 300, format: 'jpeg' %>
</p>
...
画像を投稿するフォームにファイル添付フィールドを付けます:
<%= form_for(@photo) do |f| %>
<% if @photo.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(@photo.errors.count, "error") %> prohibited this photo from being saved:</h2>
<ul>
<% @photo.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :name %><br>
<%= f.text_field :name %>
</div>
<div class="field">
<%= f.label :file %><br>
<%= f.attachment_field :file %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
以上でファイルアップロードの実装は完了です。