Help us understand the problem. What is going on with this article?

carrierwave+S3で本番環境への画像アップロード機能実装

はじめに

プロフィール画像をアップロードする機能をcarrierwavemini_magickfog-awsを用いてAWS S3にアップロードするまでの設定方法を書いていく。
本記事では前提としてユーザー管理にdevise、ビューにはSlimを使用しており、 AWS S3でバケットの作成が済んでいる状態で進める。

準備

あらかじめ本記事で用いるgemをインストールしておく。

Gemfile
gem 'carrierwave'
gem 'mini_magick'
gem 'fog-aws'
Terminal
bundle

また、Userモデルにプロフィール画像保存用のカラムとして、avatarカラムを追加しておく。
コマンドでbin/rails g migration AddAvatarToUsers avatar:stringを入力し、マイグレーションファイルを生成。

2019***********_add_avatar_to_users.rb
class AddAvatarToUsers < ActiveRecord::Migration[5.2]
  def change
    add_column :users, :avatar, :string
  end
end
Terminal
bin/rails db:migrate

手順

carrierwaveの設定

まずは画像のアップローダーを作成します。
コマンドでbin/rails g uploader Avatarと入力。
ここでは最低限の設定をしていきます。

app/uploaders/avatar_uploader.rb
class AvatarUploader < CarrierWave::Uploader::Base
  include CarrierWave::MiniMagick

  # 環境毎の画像保存先
  if Rails.env.development?
    storage :file
  elsif Rails.env.test?
    storage :file
  else
    storage :fog
  end

  # S3のディレクトリ名
  def store_dir
    "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
  end

  # 許可する画像の拡張子
  def extension_whitelist
     %w(jpg jpeg gif png)
  end

  # 保存するファイルの命名規則
  def filename
     "#{secure_token}.#{file.extension}" if original_filename.present?
  end
end

また、user.rbに以下のコードを追記し、Avatarカラムとアップローダーを紐づけ。

user.rb
class User < ApplicationRecord
  mount_uploader :avatar, AvatarUploade

続いてconfig/initializers/carrierwave.rbを作成し、AWS S3の設定書いていく。
credentialの設定方法については、credentials.yml.encでシークレットキーを管理にまとめた。

config/initializers/carrierwave.rb
if Rails.env.production?
  CarrierWave.configure do |config|
    config.fog_provider = 'fog/aws'
    config.fog_credentials = {
      provider: 'AWS',
      aws_access_key_id: Rails.application.credentials.dig(:aws, :access_key_id),
      aws_secret_access_key: Rails.application.credentials.dig(:aws, :secret_access_key),
      #S3のリージョン #ap-northeast-1はアジアパシフィック(東京)
      region: 'ap-northeast-1'
    }
    # S3のバケット名
    config.fog_directory  = 'hogehoge'
    # S3に保存しておく期間
    config.fog_attributes = { cache_control: "public, max-age=#{365.days.to_i}" }
  end
end

ストロングパラメータの設定

avatarに要素が入った状態でUserモデルが更新されるのを許可するために、ストロングパラメータの設定をする。

application_controller.rb
  protected

  def configure_permitted_parameters
    devise_parameter_sanitizer.permit(:sign_up, keys: [:username])
    devise_parameter_sanitizer.permit(:account_update, keys: [:username, :description, :avatar])
  end

ビューの設定

app/views/devise/registrations/edit.html.slim
 .circle-avatar.field
   label for="user_avatar"
     | プロフィール画像
   #img_field onclick="$('#file').click()"
     - if current_user.persisted? && current_user.avatar?
       = image_tag current_user.avatar.to_s
       = f.file_field :avatar, style: "display:none;"
     - else
       = image_tag "no_avatar.png"
       = f.file_field :avatar, style: "display:none;"

current_userdeviseの独自メソッド。
ログインユーザーがプロフィール画像を設定している場合はそれを表示し、設定していない場合に表示する画像ファイル(ここではno_avatar.pngはあらかじめ用意する
display:none;とすることで、プロフィール画像をクリックすると画像選択ができるようにする。

app/assets/stylesheets/users.scss
.circle-avatar.field img {
  width: 100px;
  height: 100px;
  border-radius: 50%;
  object-fit: cover;
}

#img_field:hover {
  transition: 0.5s ease-out;
  opacity: 0.5;
}

プロフィール画像を丸く表示し、ホバー時に半透明になるよう設定する。

最後に選択された画像を表示するための設定をする。

users.js
$(document).on("turbolinks:load", function(){
  $fileField = $('#file')
  $($fileField).on('change', $fileField, function(e) {
    file = e.target.files[0]
    reader = new FileReader(),
    $preview = $("#img_field");

    reader.onload = (function(file) {
      return function(e) {
        $preview.empty();
        $preview.append($('<img>').attr({
          src: e.target.result,
          width: "100%",
          class: "preview",
          title: file.name
        }));
      };
    })(file);
    reader.readAsDataURL(file);
  });
});

以上でアップロード昨日の実装完了。
test1.gif

参考

【Rails5】Deviseのregistrations#editで画像をアップロードする
Railsでcarrierwaveを使ってAWS S3に画像をアップロードする手順を画像付きで説明する!

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした