カテゴリー: BackEnd

RailsでS3に画像をアップロードする

はじめに

先日Railsアプリケーション上からS3に画像をアップロードする処理を実装しましたので、手順をまとめます。

 

今回やりたいこと

  1. レコード生成時にファイルを指定してアップロードする
  2. 画像のファイル名を変更する
  3. アップロード時に画像を一定サイズ内に収める
  4. アップロード時にサムネイル画像を作成する
  5. 画像の保存先、一時保存先を変更する
  6. S3にアップロードする

 

下準備

ImageMagickをインストールする

実装を始める前にImageMagickをインストールします(ImageMagickは画像のリサイズとサムネイル作成で使います)
Macで実装することを前提にしていますので、Homebrewをインストールしておいてください。

ターミナルで以下のコマンドを実行します。

brew install imagemagick

 

Gemをインストールする

次に必要なGemを追加してbundle installします。

gem 'carrierwave'
gem 'rmagick'

 

レコード生成時にファイルを指定してアップロードする

アップローダを作成する

下記のコマンドを実行し、アップローダを作成します。

rails g uploader photo_uploader

 

このコマンドを実行すると/app/uploaders/photo_uploader.rbが作成されます。

 

モデルにアップローダを関連付ける

次に画像をアップロードしたいモデルにアップローダを関連付けます。

class user < ActiveRecord::Base
  mount_uploader :profile_image, PhotoUploader
end

 

これにより、レコードを保存した際に自動的に画像がアップロードされるようになります。

 

フォームを作成する

最後に画像をアップロードするフォームを実装します。
(レコードの保存に失敗した場合、profile_image_cacheにアップロードした画像情報が格納されます)

<%= form_for @uesr do |f| %>
  <%= f.file_field :profile_image %>
  <%= f.hidden_field :profile_image_cache %>
<% end %>

 

アップロード時のオプション

画像のファイル名を変更する

PhotoUploaderに下記のメソッドを追加します。

def filename
  "#{Time.now.to_i}.jpg" if original_name
end

 

ファイル名を変更する際の注意点としては、
submitしてからレコードが保存されてアップロードした画像がリネームされるまでに上記のfilenameメソッドが複数回呼ばれるため、
ファイル名にランダム文字列を含める場合レコードに保存されたファイル名と実際のファイル名が変わってしまいます。
そのため、一度インスタンス変数に格納するなど工夫する必要があります。

 

アップロード時に画像を一定サイズ内に収める

PhotoUploaderに下記の設定を追加します。

process :resize_to_limit => [300, 300]

 

この設定では、アスペクト比を保ったまた縮小されます。

 

アップロード時にサムネイル画像を作成する

PhotoUploaderに下記の設定を追加します。

version :thumb do
  process :resize_to_limit => [100, 100]
end

 

サムネイル画像へのアクセスは下記の通りです。

<%= image_tag @user.profile_image.thumb.url %>

 

画像の保存先、一時保存先を変更する

画像の保存先の変更は下記の通りです。

def store_dir
  "images/#{model.id}/profile"
end

 

サムネイルの保存先の変更は下記の通りです。

version :thumb do
  process :resize_to_limit => [100, 100]
  def store_dir
    "images/#{model.id}/profile"
  end
end

 

画像の一時保存先の変更は下記の通りです。

def cache_dir
  'images/tmp'
end

 

サムネイルも保存先の変更と同様にブロックの中に記述します。

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を作成し、下記の通り設定を記述します。

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を使って簡単に実装できると思います。

Hiroki Ono

シェア
執筆者:
Hiroki Ono

最近の投稿

フロントエンドで動画デコレーション&レンダリング

はじめに 今回は、以下のように…

4週間 前

Goのクエリビルダー goqu を使ってみる

はじめに 最近携わっているとあ…

1か月 前

【Xcode15】プライバシーマニフェスト対応に備えて

はじめに こんにちは、suzu…

2か月 前

FSMを使った状態管理をGoで実装する

はじめに 一般的なアプリケーシ…

3か月 前