CarrierWave を利用することで手軽に画像アップロードをおこない、fog と連携してクラウド上にあるAWS S3へのアップロードをおこなえるようにします。ちなみに、S3 は新規登録から1年間は無料で利用できます。
前提として、Rails アプリにあらかじめ既存モデル(本記事ではArticle)があり、 AWS S3 でバケットを作成してある状態で進めていきます。
Amazon S3
https://aws.amazon.com/jp/s3/
CarrierWave
https://github.com/carrierwaveuploader/carrierwave
Fog::Aws
https://github.com/fog/fog-aws
rmagick
https://github.com/rmagick
環境はこちらです
1 2 3 4 5 6 |
ruby 2.5.1 rails 5.1.6 docker 18.06.0-ce carrierwave 1.2.3 fog-aws 3.0.0 rmagick 2.16.0 |
準備
本記事で必要な gem をインストールします。RMagickは画像処理を行うライブラリで、CarrierWaveからサムネイルなどを作るときに必要になります。
Gemfile
1 2 3 |
gem 'carrierwave' gem 'fog-aws' gem 'rmagick' |
1 |
$ bundle install |
画像保存用のカラムを追加するためのマイグレーションファイルを生成します。本記事では Article テーブルに追加します。
1 |
$ rails g migration add_image_to_articles image:string |
db/migrate/20xxxxxxxx_add_image_to_articles.rb
1 2 3 4 5 |
class AddImageToArticles < ActiveRecord::Migration[5.1] def change add_column :articles, :image, :string end end |
1 |
$ rails db:migrate |
アップローダの作成
次のコマンドで生成されたアップローダーをそれぞれの好みで設定してください。本番環境もしくはステージング環境で s3 に送り、開発環境等では public 配下に一時的に保存します。
1 |
$ rails g uploader Image |
app/uploaders/image_uploader.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 28 29 30 31 32 33 34 35 36 37 38 |
class ImageUploader < CarrierWave::Uploader::Base include CarrierWave::RMagick if Rails.env.production? || Rails.env.staging? storage :fog else storage :file end # S3のディレクトリ名 def store_dir "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}" end # デフォルト画像は1200x5000に収まるようリサイズ # サムネイル画像 version :thumb do process resize_to_fill: [100, 100] end # 許可する画像の拡張子 def extension_whitelist %w(jpg jpeg gif png) end # 保存するファイルの命名規則 def filename "#{secure_token}.#{file.extension}" if original_filename.present? end protected # 一意となるトークンを作成 def secure_token var = :"@#{mounted_as}_secure_token" model.instance_variable_get(var) or model.instance_variable_set(var, SecureRandom.uuid) end end |
モデルとの紐づけ
使用するモデルに次の一行を追記して、モデルとの紐づけをおこないます。
app/models/article.rb
1 2 3 4 5 |
class Article < ApplicationRecord mount_uploader :image, ImageUploader end |
AWSの設定
config/initializers/carrierwave.rb を作成して、以下のように設定します。
config/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 |
require 'carrierwave/storage/abstract' require 'carrierwave/storage/file' require 'carrierwave/storage/fog' CarrierWave.configure do |config| if Rails.env.production? config.storage :fog config.fog_provider = 'fog/aws' config.fog_directory = 'バケット名' config.fog_credentials = { provider: 'AWS', aws_access_key_id: ENV['AWS_ACCESS_KEY_ID'], aws_secret_access_key: ENV['AWS_SECRET_ACCESS_KEY'], region: ENV['AWS_REGION'], path_style: true } else config.storage :file config.enable_processing = false if Rails.env.test? end end CarrierWave::SanitizedFile.sanitize_regexp = /[^[:word:]\.\-\+]/ |
ちなみにこちらは Heroku に環境変数を入れる時のコマンドです。
1 2 |
$ heroku config:set ENV_VAR_NAME="value" # 環境変数の追加 $ heroku config # 環境変数一覧 |
ファイルのアップロード
モデル.persisted?は保存済みかどうかをチェックしてくれます。<%= f.file_field :image %> でアップロードできます。あとはお好みですが、バリデーション時も値を保持させるために <%= f.hidden_field :image_cache %> や、既存の画像を削除したい場合の <%= f.check_box :remove_image %> を追加します。
app/views/articles/_form.html.erb
1 2 3 4 5 6 7 |
<% if @article.persisted? && @article.image? %> <%= image_tag @article.image.to_s %> <label><%= f.check_box :remove_image %> 画像を削除</label> <% else %> <%= f.hidden_field :image_cache %> <% end %> <%= f.file_field :image %> |
ストロングパラメータの設定もしておきます
app/controllers/articles_controller.rb
1 2 3 4 5 6 7 |
private def article_params params.require(:article).permit( :title, :image, :image_cache, :remove_image ) end |
画像の表示
こちらもお好みですが、もし画像がない場合は no_image.png を表示させます。その画像は app/assets/images/ などに置いておきます。
app/views/articles/show.html.erb
1 2 3 4 5 |
<% if @article.image? %> <%= image_tag @article.image.to_s, class: 'mypage-article-img' %> <% else %> <%= image_tag 'no_image.png', class: 'mypage-article-img' %> <% end %> |
はい、今回は以上です!ご覧いただきありがとうございました!😆