今日やったこと17
画像の検証
画像サイズやフォーマットに対するバリデーションを実装し、サーバー用とクライアント (ブラウザ) 用の両方に追加する。
生成されたアップローダーの中のコメントアウトされたコードを取り消すことで、画像のファイル名から有効な拡張子 (PNG/GIF/JPEGなど) を検証することができる。
app/uploaders/picture_uploader.rb class PictureUploader < CarrierWave::Uploader::Base storage :file # アップロードファイルの保存先ディレクトリは上書き可能 # 下記はデフォルトの保存先 def store_dir "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}" end # アップロード可能な拡張子のリスト def extension_white_list %w(jpg jpeg gif png) end end
ファイルサイズに対するバリデーションはRailsの既存のオプション (presenceやlengthなど) にはないので、手動でpicture_sizeという独自のバリデーションを定義する。独自のバリデーションを定義するためには今まで使っていたvalidatesメソッドではなく、validateメソッドを使う。
app/models/micropost.rb class Micropost < ApplicationRecord belongs_to :user default_scope -> { order(created_at: :desc) } mount_uploader :picture, PictureUploader validates :user_id, presence: true validates :content, presence: true, length: { maximum: 140 } validate :picture_size #validateメソッドを使う private # アップロードされた画像のサイズをバリデーションする def picture_size if picture.size > 5.megabytes errors.add(:picture, "should be less than 5MB") end end end
上記で定義した画像のバリデーションをビューに組み込むために、クライアント側に2つの処理を追加する。
app/views/shared/_micropost_form.html.erb <%= form_for(@micropost) do |f| %> <%= render 'shared/error_messages', object: f.object %> <div class="field"> <%= f.text_area :content, placeholder: "Compose new micropost..." %> </div> <%= f.submit "Post", class: "btn btn-primary" %> <span class="picture"> <!-- acceptパラメータを付与する --> <%= f.file_field :picture, accept: 'image/jpeg,image/gif,image/png' %> </span> <% end %> <!-- jQueryを追加 --> <script type="text/javascript"> $('#micropost_picture').bind('change', function() { var size_in_megabytes = this.files[0].size/1024/1024; if (size_in_megabytes > 5) { alert('Maximum file size is 5MB. Please choose a smaller file.'); } }); </script>
画像のリサイズ
画像をリサイズするためには、画像を操作するプログラムが必要になる。
ImageMagickというプログラムを開発環境にインストールする。
$ sudo yum install -y ImageMagick
次に、MiniMagickというImageMagickとRubyを繋ぐgemを使って、画像をリサイズする。
app/uploaders/picture_uploader.rb class PictureUploader < CarrierWave::Uploader::Base include CarrierWave::MiniMagick # 縦横どちらかが400pxを超えていた場合、適切なサイズに縮小する process resize_to_limit: [400, 400] storage :file # アップロードファイルの保存先ディレクトリは上書き可能 # 下記はデフォルトの保存先 def store_dir "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}" end # アップロード可能な拡張子のリスト def extension_white_list %w(jpg jpeg gif png) end end
本番環境での画像アップロード
開発環境ではstorage :fileという行によって、ローカルのファイルシステムに画像を保存するようになっているが、本番環境ではファイルシステムではなくクラウドストレージサービスに画像を保存するようにする。
クラウドストレージに保存するためには、fog gemを使うと簡単できる。
app/uploaders/picture_uploader.rb class PictureUploader < CarrierWave::Uploader::Base include CarrierWave::MiniMagick process resize_to_limit: [400, 400] # 環境ごとに保存先を切り替える if Rails.env.production? storage :fog else storage :file end