画像投稿機能の実装(Docker+rails+carrierwave+fog-aws+rmagick)

目標:ユーザーのプロフィールに画像をアップロードして設定できるようにしたい

以下のGemをGemfileに記述します。

コンテナを再起動する

docker-compose stop

docker-compose down

docker-compose build
#アップローダーを生成する
docker-compose exec web rails g uploader Image

userモデルに画像をアップロードするためにimageカラムを追加します。

docker-compose run web bundle exec rails g migration AddImageToUsers user image:string

マイグレートします

docker-compose run web bundle exec rake db:migrate

CarrierWaveを導入すると、Railsのジェネレーターで画像アップローダーが生成できるようになります。

user.rbに以下の記述を追加します。

mount_uploader :image, ImageUploader

users_controllerのストロングパラメーターに以下の記述を追加します。

def user_params
  params.require(:user).permit(:name, :email, :password,
                               :password_confirmation, :image, :image_cache)
end

image_uploader.rbに以下の記述を追加

class ImageUploader < CarrierWave::Uploader::Base

# 画像サイズを取得するためにRMagick使用
  include CarrierWave::RMagick

# このアップローダで使用するストレージの種類を選択します。
# developmentとtest以外はS3を使用
if Rails.env.development? || Rails.env.test?
  storage :file
else
  storage :fog
end

# アップロードされたファイルが保存されるディレクトリを上書きします。
# これは、マウントされることを前提としたアップローダのための、賢明なデフォルトです。
# 画像ごとに保存するディレクトリを変える
def store_dir
  "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
end

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

#画像の最大サイズを5MB未満にする
def size_range
  1..5.megabytes
end

# 画像の上限を640x480にする
process :resize_to_limit => [640, 480]

# 保存形式をJPGにする
process :convert => 'jpg'

# サムネイルを生成する設定edit用
version :thumb do
  process :resize_to_limit => [400, 400]
end
# ユーザー管理画面用
version :thumb100 do
  process :resize_to_limit => [100, 100]
end

# 拡張子が同じでないとGIFをJPGとかにコンバートできないので、ファイル名を変更
def filename
  super.chomp(File.extname(super)) + '.jpg' if original_filename.present?
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/views/users/new.html.erbに以下の記述を追加
<%= form_with model: @user, local: true do |f| %>
  <%= image_tag @user.image.thumb.url if @user.image? %>
  <%= render 'shared/error_messages', object: f.object %>
  <div class="inputWithIcon">
    <%= f.text_field :name, class: 'form-field', placeholder: 'Your name' %>
    <%= f.email_field :email, class: 'form-field', placeholder: 'Email' %>
    <%= f.password_field :password, class: 'form-field', placeholder: 'パスワード' %>
    <%= f.password_field :password_confirmation, class: 'form-field', placeholder: 'パスワード確認' %>
  </div>
  <%= f.label :プロフィール画像をアップロードできます。 %>
  <div class="file-upload_area">
    <%= f.file_field :image, class: 'file-upload_input' %>
    <%= f.hidden_field :image_cache %>
  </div>
  <div class="center-position">
    <%= f.submit yield(:button_text), class: " btn float" %>
  </div>

:image_cacheは

他の入力項目のバリデーションに引っかかった時、もう1回画像をアップロードしなくても良くなる
/app/views/users/show.html.erbの記述
<% @users.each do |user| %>
    <%= user.name %>
    <%= user.email %>
    <% if user.image? %>
      <%= image_tag user.image.thumb100.url %>
    <% end %>

ユーザー管理画面に画像が反映されていればOK

編集画面app/views/users/edit.html.erbに以下の記述を追加

<%= user.text_field :name, class: 'form-field', placeholder: 'Your name' %>
<%= user.email_field :email, class: 'form-field', placeholder: 'Email' %>
<%= user.password_field :password, class: 'form-field', placeholder: 'パスワード' %>
<%= user.password_field :password_confirmation, class: 'form-field', placeholder: 'パスワード確認' %>
<%= user.label :プロフィール画像を変更できます。 %>
  <div class="file-upload_area">
<%= user.file_field :image, class: 'file-upload_input' %>
  </div>
<%= user.submit yield(:button_text), class: "btn float" %>
    <% if logged_in? && !guest_user %>
<%= link_to "退会", @user, method: :delete,
          data: { confirm: "本当に退会しますか?" } %>
    <% end %>

ファイルを選択して編集できていればOKです!

/config/locales/carrierwave_ja.ymlに以下の記述を追加

ja:
  errors:
    messages:
      record_invalid: 'バリデーションに失敗しました: %{errors}'
      restrict_dependent_destroy:
        has_one: "%{record}が存在しているので削除できません"
        has_many: "%{record}が存在しているので削除できません"
      carrierwave_processing_error: "処理できませんでした"
      carrierwave_integrity_error: "は許可されていないファイルタイプです"
      carrierwave_download_error: "はダウンロードできません"
      extension_whitelist_error: "%{extension}ファイルのアップロードは許可されていません。アップロードできるファイルタイプ: %{allowed_types}"
      extension_blacklist_error: "%{extension}ファイルのアップロードは許可されていません。アップロードできないファイルタイプ: %{prohibited_types}"
      content_type_whitelist_error: "%{content_type}ファイルのアップロードは許可されていません"
      content_type_blacklist_error: "%{content_type}ファイルのアップロードは許可されていません"
      rmagick_processing_error: "rmagickがファイルを処理できませんでした。画像を確認してください。エラーメッセージ: %{e}"
      mini_magick_processing_error: "MiniMagickがファイルを処理できませんでした。画像を確認してください。エラーメッセージ: %{e}"
      min_size_error: "ファイルを%{min_size}以上のサイズにしてください"
      max_size_error: "ファイルを%{max_size}未満のサイズにしてください"
date:

エラーが日本語で表示されたのを確認したらOKです!

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です