はじめに
Paperclip を使い、取り扱う全ての画像を一括で管理する Picture モデル (ポリモーフィック継承) で、
保存される画像についてそれぞれ異なるアスペクト比をチェックする方法を実装した時のメモ。
実装内容
User のプロフィール画像は、正方形 (縦横は 1 対 1 ) を保持できる
※ 200 × 200 等の画像
Item の画像は、長方形 ( 縦横は 5 対 8 ) を保持できる
※ 400 × 640 等の画像
サンプルソース
class User < ActiveRecord::Base
has_one :profile_image, class_name: Picture, as: :holder, dependent: :destroy
accepts_nested_attributes_for :profile_image, allow_destroy: true
end
class Item < ActiveRecord::Base
has_many :pictures, as: :holder, dependent: :destroy
accepts_nested_attributes_for :pictures, allow_destroy: true
end
class Picture < ActiveRecord::Base
WIDTHS = %i{640 200 142 80}
STYLES = WIDTHS.map {|width| [:"w#{width}", "#{width}x>"]}.to_h
PICTURE_TYPES = { user: 1, item: 0.625 } # height / width
CONTENT_TYPE = %w{image/jpeg image/jpg image/png image/gif}
belongs_to :holder, polymorphic: true
has_attached_file :image, { styles: STYLES }
validates_attachment_size :image, less_than: 1.5.megabytes
validates_attachment_content_type :image, content_type: CONTENT_TYPE
validate :validate_image_aspect_ratio, if: -> { image.present? && CONTENT_TYPE.include?(image_content_type) & holder.present? }
private
def validate_image_aspect_ratio
key = holder_type.underscore.to_sym
if PICTURE_TYPES.keys.include?(key)
geometry = Paperclip::Geometry.from_file(image.queued_for_write[:original])
errors.add(:image, :invalid_aspect_ratio) unless PICTURE_TYPES[key] == (geometry.height / geometry.width)
end
end
end
サンプルの説明
PICTURE_TYPES
で holder
に当たる user
と item
のアスペクト比 ( 縦横比 ) を記載し、
validate_image_aspect_ratio
でそれらをチェックしています。
image.queued_for_write[:original]
でオリジナルのファイルから Paperclip::Geometry
オブジェクトを
生成し、縦横のサイズをを取得し、チェックしています。
今後、holder
に入るモデルが増える場合は、PICTURE_TYPES
にそれぞれ追加することで対応できます。
ただし、1つのモデルが、複数のアスペクト比の画像ファイルを保存できるようになっていないので、
その場合は、下記のよう感じに修正すれば出来るはず。。。チェックしてませんが。
PICTURE_TYPES = { user: [1, 1.6], item: [0.625] } # user に正方形の他の 640 × 400 も追加
errors.add(:image, :invalid_aspect_ratio) unless PICTURE_TYPES[key].include?(geometry.height / geometry.width)