いわりょのBlog

IT関連で学んだことを書いていきます。

carrierwaveで画像投稿できるようにする

作ったもの

こちらのように商品などの投稿システムには欠かせない「画像投稿機能」を実装していきます。

Gemインストール

バージョンも指定しております。
mini_magickと本番環境でのアップロード用のfogも入れています。

Gemfile

gem 'carrierwave',             '1.2.2'
gem 'mini_magick',             '4.7.0'
・
・
・
group :production do
  (省略)
  gem 'fog', '1.42'
end
bundle install

アップローダーの作成

これで画像アップローダーが作成できるようになったので作っていきます。

rails generate uploader ProductPicture

作成できました。

データモデルの設定

今回は実際に使っているProductモデルを例にします。
完成形のデータモデルは下記の通りです。
f:id:Ryo10Leo:20200105202750p:plain
画像の情報はpictureカラムが持っています。
pictureカラムがなかったらrailsコマンドで作成

$ rails generate migration add_picture_to_product picture:string
$ rails db:migrate

CarrierWaveでアップロードされた画像は、Productモデルのpicture属性と関連付けされているべきなので、そのためにmount_uploaderというメソッドを使います。属性名のシンボルと生成されたアップローダーのクラス名を取ります。

mount_uploader :picture, ProductPictureUploader

↑このように書かれます。

product.rbファイルに書いていきます。

app/models/product.rb

class Product < ApplicationRecord

   (中略)

    validates :picture, presence: true ←画像なし無効化
    mount_uploader :picture, ProductPictureUploader
end

商品投稿なので画像なし避けるため、バリデーションも追加しています。

railsサーバーを一度再起動します。

フォームに画像を選択できるようにする

動画では画像選択フィールドでサムネが表示されてますが、その実装は長くなるのでまたの機会に笑

今回は無難にfile_fieldを追加します。

app/views/products/new.html.erb

    <%= form_for(@product) do|f| %>

    <%= render'shared/error_messages',object: f.object %>

    <div class="form-group">
        <%= f.label "商品名" %>
        <%= f.text_field :name ,class: 'form-control' %>
    </div>

    <div class="form-group">
        <%= f.label "定価" %>
        <%= f.text_field :price ,class: 'form-control' %>
    </div>
     
     (中略)
* 画像の表示
     #既存のフォームビューに追加
  <span class="picture">
    <%= f.file_field :picture %>
   </span>

   <% end %>

あとは投稿が成功していれば、表示させたいテンプレートにimage_tagを使えば表示させることができます。

自分が使っているテンプレートを例にすると

_product.html.erb

<div class="item">

    <%= image_tag @product.picture %>
    <p><%= @product.name %></p>

</div>

@productにはProductのインスタンスが入っています。
このようにimage_tagのソースに@product.pictureとすれば表示させることができます。

本番環境での画像アップロード

本番環境ではクラウドストレージサービスに画像を保存するようにします。
先ほどインストールしたgemのfogを使うとクラウドストレージに保存することが簡単にできます。
設定は下記の通り

product_picture_uploader.rb

class ProductPictureUploader < CarrierWave::Uploader::Base
  include CarrierWave::MiniMagick

#開発環境ではローカルファイルに
#本番ではクラウドストレージサービスを利用
  if Rails.env.production?
    storage :fog
  else
    storage :file
  end
・
・
・
end

クラウドストレージサービスにはAmazon web ServiceのS3を使いました。

AWSの設定方法などはまた他の記事でかけたらと、、、

AWSでやることは

  1. IAMでユーザーを作成し、AccessキーとSecretキーゲット
  2. bucketを作成。
  3. 作成したユーザーに対してbucketのRead権限とWrite権限を付与

この3点ができたら、CarrierWaveの設定ファイルに画像の保存をS3を使うように設定していきます。

if Rails.env.production?
    CarrierWave.configure do |config|
      config.fog_credentials = {
        # Amazon S3用の設定
        :provider              => 'AWS',
        :region                => ENV['S3_REGION'],     # 例: 'ap-northeast-1'
        :aws_access_key_id     => ENV['S3_ACCESS_KEY'],
        :aws_secret_access_key => ENV['S3_SECRET_KEY']
      }
      config.fog_directory     =  ENV['S3_BUCKET']
    end
  end

これは情報漏洩を防ぐために、環境変数を使用しています。

Herokuを使っている場合は、下記のように環境変数の設定をしましょう。

$ heroku config:set S3_ACCESS_KEY="Accessキー"
$ heroku config:set S3_SECRET_KEY="Secretキー"
$ heroku config:set S3_BUCKET="Bucketの名前"
$ heroku config:set S3_REGION="Regionの名前"

これで設定は完了!

最後に画像を保存するディレクトリをGitへの保存対象から外します。

.gitignore
.
.
.
# アップロードされたテスト画像を無視する
/public/uploads

気づいたことがあれば、そのつど追記します。