CarrierWave でファイルアップロード
Scaffold で作成した CRUD に、CarrierWave でファイルアップロード機能を追加します。
Railsの環境はRails + Unicorn + Nginx - われプログラミングする、ゆえにバグありを参照してください。
Scaffold で Model と CRUD を作成する
$ bundle exec rails g scaffold photo image:string description:text
db:migrate を実行しておきます
$ bundle exec rake db:migrate
"photo" model の "image" フィールドで画像ファイルを扱います。
ここではまだ "image" は String のフィールドです。
Webブラウザで "http://[host_name]/photos" を開いて、photo Model の CRUD 機能を確認しておきましょう。
CarrierWave の gem を追加
$ vim Gemfile
# 最終行に追加 gem 'carrierwave'
bundle install を実行しておきます
$ bundle install
Uploaderクラスを生成
$ bundle exec rails g uploader image
# -> "app/uploaders/image_uploader.rb" というファイルが生成されます
Model を編集
$ vim app/model/photo.rb
class Photo < ActiveRecord::Base + mount_uploader :image, ImageUploader end
View を編集
$ vim app/views/photos/_form.html.erb
# 1行目あたり - <%= form_for(@photo) do |f| %> + <%= form_for(@photo, html: {multipart: true}) do |f| %> # 16行目あたり - <%= f.text_field :iamge %> + <%= f.file_field :iamge %>
$ vim app/views/photos/show.html.erb
# 5行目あたり - <%= @photo.image %> + <%= image_tag @photo.image.url %>
以上で単純なファイルアップロード機能ができました。
その他の設定
アップロードされるファイルを画像に限定する
ファイル名の拡張子をチェックするだけです
$ vim app/uploaders/image_uploader.rb
# 41行目あたりをアンコメント - #def extension_white_list - # %w(jpg jpeg gif png) - #end + def extension_white_list + %w(jpg jpeg gif png) + end
アップロードしたファイルを削除できるようにする
$ vim app/views/photos/_form.html.erb
# 18行目あたり </div> + <div class="field"> + <%= f.label :remove_image %> + <%= f.check_box :remove_iamge %> + </div> <div class="field">
$ vim app/controllers/photos_controller.rb
# 72行目あたり - params.require(:photo).permit(:image, :description) + params.require(:photo).permit(:image, :remove_image, :description)
登録時のファイルをキャッシュする
登録時にValidationに引っ掛かって登録画面を再表示したときに、ファイルを再度選択しなくてもよくする
$ vim app/views/photos/_form.html.erb
# 17行目あたり <%= f.file_field :image %> + <%= f.hidden_field :image_cache %>
$ vim app/controllers/photos_controller.rb
# 72行目あたり - params.require(:photo).permit(:image, :remove_image, :description) + params.require(:photo).permit(:image, :image_cache, :remove_image, :description)
登録の際にユニークなファイル名を付ける
クライアントがファイルをキャッシュする対策
$ vim app/uploaders/image_uploader.rb
参考 CarrierWaveで一意な名前をつけて画像を保存 | デジタネイティブ
# 47行目あたり - # def filename - # "something.jpg" if original_filename - # end + def filename + "#{secure_token}.#{file_extension}" if original_filename.present? + end + + protected + def secure_token + var = :"@#{mounted_as}_secure_token" + model.instance_variable_get(var) or model.instance_variable_set(var, SecureRandom.uuid) + end
※ 新規登録の際、filename メソッドは model の id が確定していない状態で呼ばれるので、model.id は filename で使えない
まとめ
CarrierWave の機能として、他にリサイズ、サムネイルの作成等があります。