はじめに
先日Railsアプリケーション上からS3に画像をアップロードする処理を実装しましたので、手順をまとめます。
今回やりたいこと
- レコード生成時にファイルを指定してアップロードする
- 画像のファイル名を変更する
- アップロード時に画像を一定サイズ内に収める
- アップロード時にサムネイル画像を作成する
- 画像の保存先、一時保存先を変更する
- S3にアップロードする
下準備
ImageMagickをインストールする
実装を始める前にImageMagickをインストールします(ImageMagickは画像のリサイズとサムネイル作成で使います)
Macで実装することを前提にしていますので、Homebrewをインストールしておいてください。
ターミナルで以下のコマンドを実行します。
1 | brew install imagemagick |
Gemをインストールする
次に必要なGemを追加してbundle installします。
1 2 | gem 'carrierwave' gem 'rmagick' |
レコード生成時にファイルを指定してアップロードする
アップローダを作成する
下記のコマンドを実行し、アップローダを作成します。
1 | rails g uploader photo_uploader |
このコマンドを実行すると/app/uploaders/photo_uploader.rbが作成されます。
モデルにアップローダを関連付ける
次に画像をアップロードしたいモデルにアップローダを関連付けます。
1 2 3 | class user < ActiveRecord::Base mount_uploader :profile_image, PhotoUploader end |
これにより、レコードを保存した際に自動的に画像がアップロードされるようになります。
フォームを作成する
最後に画像をアップロードするフォームを実装します。
(レコードの保存に失敗した場合、profile_image_cacheにアップロードした画像情報が格納されます)
1 2 3 4 | <%= form_for @uesr do |f| %> <%= f.file_field :profile_image %> <%= f.hidden_field :profile_image_cache %> <% end %> |
アップロード時のオプション
画像のファイル名を変更する
PhotoUploaderに下記のメソッドを追加します。
1 2 3 | def filename "#{Time.now.to_i}.jpg" if original_name end |
ファイル名を変更する際の注意点としては、
submitしてからレコードが保存されてアップロードした画像がリネームされるまでに上記のfilenameメソッドが複数回呼ばれるため、
ファイル名にランダム文字列を含める場合レコードに保存されたファイル名と実際のファイル名が変わってしまいます。
そのため、一度インスタンス変数に格納するなど工夫する必要があります。
アップロード時に画像を一定サイズ内に収める
PhotoUploaderに下記の設定を追加します。
1 | process :resize_to_limit => [300, 300] |
この設定では、アスペクト比を保ったまた縮小されます。
アップロード時にサムネイル画像を作成する
PhotoUploaderに下記の設定を追加します。
1 2 3 | version :thumb do process :resize_to_limit => [100, 100] end |
サムネイル画像へのアクセスは下記の通りです。
1 | <%= image_tag @user.profile_image.thumb.url %> |
画像の保存先、一時保存先を変更する
画像の保存先の変更は下記の通りです。
1 2 3 | def store_dir "images/#{model.id}/profile" end |
サムネイルの保存先の変更は下記の通りです。
1 2 3 4 5 6 | version :thumb do process :resize_to_limit => [100, 100] def store_dir "images/#{model.id}/profile" end end |
画像の一時保存先の変更は下記の通りです。
1 2 3 | def cache_dir 'images/tmp' end |
サムネイルも保存先の変更と同様にブロックの中に記述します。
1 2 3 4 5 6 7 8 9 | version :thumb do process :resize_to_limit => [100, 100] def store_dir "images/#{model.id}/profile" end def cache_dir 'images/tmp' end end |
S3にアップロードする
initializerの設定を行います。
/initializers/carrierwave.rbを作成し、下記の通り設定を記述します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | CarrierWave.configure do |config| if Rails.env.production? config.storage = :aws config.aws_bucket = 'data.hoge.upload' config.aws_acl = 'public-read' # The maximum period for authenticated_urls is only 7 days. config.aws_authenticated_url_expiration = 60 * 60 * 24 * 7 # Set custom options such agit s cache control to leverage browser caching config.aws_attributes = { expires: 1.week.from_now.httpdate, cache_control: 'max-age=604800' } # aws credential config.aws_credentials = { # 今回はIAM ロールを使用するため記載しない # access_key_id: ENV.fetch('AWS_ACCESS_KEY_ID'), # secret_access_key: ENV.fetch('AWS_SECRET_ACCESS_KEY'), region: 'ap-northeast-1' # Required } else # テスト時はローカルにファイルを保存する config.storage = :file end end |
さいごに
CarrierWaveを使って画像をアップロードする方法をまとめました。
一般的な使い方であれば、CarrierWaveを使って簡単に実装できると思います。