学習日記

Ruby on Rails勉強してます

今日やったこと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というImageMagickRubyを繋ぐ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