railsで写真アップロード機能を実装
環境
手順
写真アップロード用モデルを作成
$ rails g scaffold Picture date:datetime
DBのマイグレートを実行
$ rake db:migrate
サーバーを起動してブラウザでアクセスしてみる
$ rails s
http://localhost:3000/pictures
登録ページが表示されていればここまではOK
Gemのインストール
では、CarrierWaveのインストールをプロジェクトに導入します。
$ vi Gemfile
...
gem "carrierwave"
gemをインストール
$ bundle install
アップローダーの生成
CarrierWaveのジェネレーターでアップローダーを作成する
$ rails g uploader Image
create app/uploaders/image_uploader.rb
作成されたファイルのimage_uploader.rbの中をのぞいてみると、ファイルの保存方法(デフォルトはファイル)、保存パス、ファイルのサイズ、拡張子やファイル名の変換などが変更できることがわかる。
CarrierWaveはActiveRecordやMongoId、DataMapperなどのORMと連携することができる。 今回は、RailsのデフォルトでもあるActiveRecordを使って、アップロードしたファイルの情報を保存してみる。
Modelに画像情報保持用のカラムの追加
まずは、Stringカラムをモデルに追加するために、Pictureモデルにマイグレーションファイルを作成し、マイグレート
$ rails g migration add_image_to_picture image:string
$ rake db:migrate
その後、モデルファイルを開き、アップローダーへのマウントする記述を追加
$ app/models/picture.rb
class Picture < ActiveRecord::Base
mount_uploader :image, ImageUploader
end
画像の追加/編集/表示/削除処理の追加
写真の新規/編集フォームに画像アップロードの入力フィールドを追加する。 hidden属性でimage_cacheを指定しましたが、これは、画像を指定したけれども、バリデーションエラーなどにより保存が失敗した場合の画面再表示時などに、画像情報をキャッシュしておくための領域となる。
$ cat app/views/pictures/_form.html.erb
<%= form_for(@picture) do |f| %>
<% if @picture.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(@picture.errors.count, "error") %> prohibited this picture from being saved:</h2>
<ul>
<% @picture.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :date %><br>
<%= f.datetime_select :date %>
</div>
<!-- 追加個所 -->
<div class="field">
<% if @picture.image? %>
<div class="thumbnail">
<%= image_tag @picture.image.url %>
</div>
<% end %><br>
<%= f.label :image %><br>
<%= f.file_field :image %>
<%= f.hidden_field :image_cache %>
</div>
<div class="field">
<!-- 既存レコード(DBに保存されている)かつ、画像が存在する場合 -->
<% if @picture.persisted? && @picture.image? %>
<label>
<%= f.check_box :remove_image %>
画像を削除
</label>
<% end %>
</div>
<!-- 追加個所終了 -->
<div class="actions">
<%= f.submit %>
</div>
<% end %>
コントローラーにファイルの属性を更新できるようにするために、StrongParametersの箇所を修正
$ app/controllers/pictures_controller.rb
...
# Never trust parameters from the scary internet, only allow the white list through.
def picture_params
# params.require(:picture).permit(:date)
params.require(:picture).permit(:date, :image, :image_cache, :remove_image)
end
そして、画像がアップロードされたら、詳細画面で表示するようにします。
$ vi app/views/pictures/show.html.erb
<p id="notice"><%= notice %></p>
<p>
<strong>Date:</strong>
<%= @picture.date %>
</p>
<!-- 追加箇所 開始 -->
<p>
<strong>Image:</strong>
<% if @picture.image? %>
<div class="thumbnail">
<%= image_tag @picture.image.url %>
</div>
<% end %>
</p>
<!-- 追加箇所 終了 -->
<%= link_to 'Edit', edit_picture_path(@picture) %> |
<%= link_to 'Back', pictures_path %>
end
サーバーを起動してhttp://localhost:3000/picturesにアクセス
新規作成で、写真のアップロードや削除ができる
また、このアップロードされたファイルはpublic/uploads/products配下に保存されている
### CarrierWaveの良く使うメソッド
アップローダーをincludeしたモデル次のようなメソッドを使える
#### モデルの作成
product = Product.new
#### 画像ファイルの設定
product.image = params[:image] # paramsから設定
product.image = File.open('somewhere') # Fileオブジェクトを設定
#### 保存
product.save!
#### アップローダーの対するメソッド
product.image.url # => '/url/to/file.png'
product.image.current_path # => 'path/to/file.png'
prodcut.image.identifier # => 'file.png'
product.image? # => imageがあるかを true or false で返す
今回はCarrierWaveの基礎的な内容を記載したが、比較的簡単に画像のCRUDをActiveRecordのモデルに追加することができることがわかった。