【Rails5】carrierwaveとfogでAWS S3に画像を複数アップロードする方法 #rails #画像アップロード version 1

2019/11/09 13:35 by michiru michiru
  :追加された部分   :削除された部分
(差分が大きい場合、文字単位では表示しません)
【Rails5】cariierwaveとfogでAWS S3に画像を複数アップロードする方法
![2019-11-09 (3)](https://mimemo.s3-ap-northeast-1.amazonaws.com/attachment/8ad4286e-b466-4289-bc3c-e87c9b8f0d89.png)
***
### 1. 画像アップロード用のカラムを作成するため「rails g migration add_images_column_to_テーブル名 images:string」をターミナルで実装する
```
$ rails g migration add_images_column_to_boards images:string  
```
※今回は複数の画像を一度にアップロードさせたいためカラム名は「images」とし、テーブル名は「boards」とする。
### 2. Gemfileに'carrierwave'と'fog-aws'を追加しbundle installを実行する
'carrierwave'を利用することで手軽に画像をアップロードすることができ、fogと連携することでクラウド上にあるAWS S3への画像をアップロードできるようにする。
```:Gemfile=53
gem 'carrierwave'
gem 'fog-aws'
```
```
$ bundle install
```
### 3. 画像アップロード用のクラスを作成すつために「rails g uploader アップローダー名」をターミナルで実装する
```
$ rails g uploader image
```
画像アップローダーとは以下のようなものである。
![07-17-2017-1500241058](https://mimemo.s3-ap-northeast-1.amazonaws.com/attachment/3deddc02-f39f-4c94-afcb-4d12fe38d10d.png)
### 4. アップローダーを実装したいクラス(ここではboardクラス)に以下のコードを記述する

```:/app/models/board.rb=1
class Board < ApplicationRecord
  mount_uploaders :images, ImgUploader
  serialize :images, JSON //複数の画像をアップロードをする場合は左の1文が必要である 
  belongs_to :user
end
```
serialize「シリアル化」とは複数の並列データを直列化して送信することであり、JSONとはJavaScript Object Notationの略でデータフォーマットの一種である。{}波括弧で括りその中にデータが入る形式であり以下のようなものになる。
```
{
    "user": "太郎",
    "age": 20,
    "gender": "男"
}
```
### 5. ストロングパラメーターに「images」カラムを追加する
* 複数の画像をアップロードする場合はデータをJSON形式で保存する必要があるため、ストロングパラメーターには{images: []}と書く。
```:/controllers/boards_controller.rb=1
class BoardsController < ApplicationController
before_action :authenticate_user!, :only => [:new, :create]
    
    def new
    @board = Board.new
    end

    def index
    @boards = Board.all
    end
    
    def create
      @board = Board.new(board_params)
      @board.user_id=current_user.id
      if @board.save
          flash[:notice] = "掲示板に新規投稿されました"
          redirect_to boards_path
      else 
          flash[:notice] = "掲示板に新規投稿できませんでした"
          render :new
      end
    end

    def show
    @board = Board.find(params[:id])
    @user = User.find(@board.user_id)
    end
   
 private 
    def board_params
      params.require(:board).permit({images: []}, :title, :book_name, :author, :isbn_num, :category, :condition, :available_period, :remarks, :user_id).merge(:user_id => current_user.id)
    end

end
```
* 一枚の画像だけをアップロードしたい場合、カラム名は「:image」となる。その場合はストロングパラメーターに以下のような実装をする。
```
   def board_params
      params.require(:board).permit(:image, :title,.......
```
### 6. アップローダーを実装したいviewと、画像を表示したいviewを編集する
```:/app/views/boards/new.html.erb=20
<%= f.label :images, "画像:" %>
<%= f.file_field :images, multiple: true, accept: "image/*" %>
```
「multiple: true」とすることで複数の画像がアップロードできる。「accept: "image/*"」とすることで画像ファイルしかアップロードできないようにする。
```:/app/views/boards/show.html.erb=5
画像:
<% @board.images.each do |image| %>
 <%= image_tag image, class: "board-images" %>
<% end %>
```
```:/app/stylesheets/styles.scss=1
.board-images {
  display: inline-block;
  width: 200px;
  height: 200px;
}
```
***
### 7. image_uploader.rbにある「storage :fog」をコメントアウトする
```:/uploaders/image_uploader.rb=1
class ImgUploader < CarrierWave::Uploader::Base
  # Include RMagick or MiniMagick support:
  # include CarrierWave::RMagick
  # include CarrierWave::MiniMagick

  # Choose what kind of storage to use for this uploader:
  # storage :file
  storage :fog

  # Override the directory where uploaded files will be stored.
  # This is a sensible default for uploaders that are meant to be mounted:
  def store_dir
    "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
  end

  # Provide a default URL as a default if there hasn't been a file uploaded:
  # def default_url(*args)
  #   # For Rails 3.1+ asset pipeline compatibility:
  #   # ActionController::Base.helpers.asset_path("fallback/" + [version_name, "default.png"].compact.join('_'))
  #
  #   "/images/fallback/" + [version_name, "default.png"].compact.join('_')
  # end

  # Process files as they are uploaded:
  # process scale: [200, 300]
  #
  # def scale(width, height)
  #   # do something
  # end

  # Create different versions of your uploaded files:
  # version :thumb do
  #   process resize_to_fit: [50, 50]
  # end

  # Add a white list of extensions which are allowed to be uploaded.
  # For images you might use something like this:
  def extension_whitelist
    %w(jpg jpeg gif png)
  end

  # Override the filename of the uploaded files:
  # Avoid using model.id or version_name here, see uploader/store.rb for details.
  # def filename
  #   "something.jpg" if original_filename
  # end
end
```
### 8. initializersのファイル直下にcarrierwave.rbを自分で作成し以下をコピペする
config.fog_directory には自分のbucket名を入れる。
```:/initializers/carrierwave.rb=1
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  = '_bucket' #自分のbucketの名前を入れる
    config.fog_credentials = {
      provider: 'AWS',
      aws_access_key_id: ENV['AWS_ACCESS_KEY_ID'],
      aws_secret_access_key: ENV['AWS_SECRET_ACCESS_KEY'],
      region: 'ap-northeast-1', #日本の場合はregionはこのように設定
      path_style: true
    }
#   else
#     config.storage :file
#     config.enable_processing = false if Rails.env.test?
#   end
end
 
CarrierWave::SanitizedFile.sanitize_regexp = /[^[:word:]\.\-\+]/
```
### 9. AWS S3へのアクセス環境変数設定をするため以下をターミナルで実行する
```
$ export AWS_ACCESS_KEY_ID=自分のbucketのACCESS_KEY_IDを入れる
$ export AWS_SECRET_ACCESS_KEY=自分のbucketのSECRET_ACCESS_KEYを入れる
```
※以上の実装はAWSS3にbucketを作成してからでないとできないので注意。
***
不明点、修正点ございましたらコメントよろしくお願いします。
      

2019-11-09 (3)


1. 画像アップロード用のカラムを作成するため「rails g migration add_images_column_to_テーブル名 images:string」をターミナルで実装する

$ rails g migration add_images_column_to_boards images:string  

※今回は複数の画像を一度にアップロードさせたいためカラム名は「images」とし、テーブル名は「boards」とする。

2. Gemfileに'carrierwave'と'fog-aws'を追加しbundle installを実行する

'carrierwave'を利用することで手軽に画像をアップロードすることができ、fogと連携することでクラウド上にあるAWS S3への画像をアップロードできるようにする。

gem 'carrierwave'
gem 'fog-aws'
53 54Gemfile
$ bundle install

3. 画像アップロード用のクラスを作成すつために「rails g uploader アップローダー名」をターミナルで実装する

$ rails g uploader image

画像アップローダーとは以下のようなものである。
07-17-2017-1500241058

4. アップローダーを実装したいクラス(ここではboardクラス)に以下のコードを記述する

class Board < ApplicationRecord
  mount_uploaders :images, ImgUploader
  serialize :images, JSON //複数の画像をアップロードをする場合は左の1文が必要である 
  belongs_to :user
end
1 2 3 4 5/app/models/board.rb

serialize「シリアル化」とは複数の並列データを直列化して送信することであり、JSONとはJavaScript Object Notationの略でデータフォーマットの一種である。{}波括弧で括りその中にデータが入る形式であり以下のようなものになる。

{
    "user": "太郎",
    "age": 20,
    "gender": "男"
}

5. ストロングパラメーターに「images」カラムを追加する

  • 複数の画像をアップロードする場合はデータをJSON形式で保存する必要があるため、ストロングパラメーターには{images: []}と書く。
class BoardsController < ApplicationController
before_action :authenticate_user!, :only => [:new, :create]
    
    def new
    @board = Board.new
    end

    def index
    @boards = Board.all
    end
    
    def create
      @board = Board.new(board_params)
      @board.user_id=current_user.id
      if @board.save
          flash[:notice] = "掲示板に新規投稿されました"
          redirect_to boards_path
      else 
          flash[:notice] = "掲示板に新規投稿できませんでした"
          render :new
      end
    end

    def show
    @board = Board.find(params[:id])
    @user = User.find(@board.user_id)
    end
   
 private 
    def board_params
      params.require(:board).permit({images: []}, :title, :book_name, :author, :isbn_num, :category, :condition, :available_period, :remarks, :user_id).merge(:user_id => current_user.id)
    end

end
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/controllers/boards_controller.rb
  • 一枚の画像だけをアップロードしたい場合、カラム名は「:image」となる。その場合はストロングパラメーターに以下のような実装をする。
   def board_params
      params.require(:board).permit(:image, :title,.......

6. アップローダーを実装したいviewと、画像を表示したいviewを編集する

<%= f.label :images, "画像:" %>
<%= f.file_field :images, multiple: true, accept: "image/*" %>
20 21/app/views/boards/new.html.erb

「multiple: true」とすることで複数の画像がアップロードできる。「accept: "image/*"」とすることで画像ファイルしかアップロードできないようにする。

画像:
<% @board.images.each do |image| %>
 <%= image_tag image, class: "board-images" %>
<% end %>
5 6 7 8/app/views/boards/show.html.erb
.board-images {
  display: inline-block;
  width: 200px;
  height: 200px;
}
1 2 3 4 5/app/stylesheets/styles.scss

7. image_uploader.rbにある「storage :fog」をコメントアウトする

class ImgUploader < CarrierWave::Uploader::Base
  # Include RMagick or MiniMagick support:
  # include CarrierWave::RMagick
  # include CarrierWave::MiniMagick

  # Choose what kind of storage to use for this uploader:
  # storage :file
  storage :fog

  # Override the directory where uploaded files will be stored.
  # This is a sensible default for uploaders that are meant to be mounted:
  def store_dir
    "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
  end

  # Provide a default URL as a default if there hasn't been a file uploaded:
  # def default_url(*args)
  #   # For Rails 3.1+ asset pipeline compatibility:
  #   # ActionController::Base.helpers.asset_path("fallback/" + [version_name, "default.png"].compact.join('_'))
  #
  #   "/images/fallback/" + [version_name, "default.png"].compact.join('_')
  # end

  # Process files as they are uploaded:
  # process scale: [200, 300]
  #
  # def scale(width, height)
  #   # do something
  # end

  # Create different versions of your uploaded files:
  # version :thumb do
  #   process resize_to_fit: [50, 50]
  # end

  # Add a white list of extensions which are allowed to be uploaded.
  # For images you might use something like this:
  def extension_whitelist
    %w(jpg jpeg gif png)
  end

  # Override the filename of the uploaded files:
  # Avoid using model.id or version_name here, see uploader/store.rb for details.
  # def filename
  #   "something.jpg" if original_filename
  # end
end
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 39 40 41 42 43 44 45 46 47/uploaders/image_uploader.rb

8. initializersのファイル直下にcarrierwave.rbを自分で作成し以下をコピペする

config.fog_directory には自分のbucket名を入れる。

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  = '_bucket' #自分のbucketの名前を入れる
    config.fog_credentials = {
      provider: 'AWS',
      aws_access_key_id: ENV['AWS_ACCESS_KEY_ID'],
      aws_secret_access_key: ENV['AWS_SECRET_ACCESS_KEY'],
      region: 'ap-northeast-1', #日本の場合はregionはこのように設定
      path_style: true
    }
#   else
#     config.storage :file
#     config.enable_processing = false if Rails.env.test?
#   end
end
 
CarrierWave::SanitizedFile.sanitize_regexp = /[^[:word:]\.\-\+]/
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23/initializers/carrierwave.rb

9. AWS S3へのアクセス環境変数設定をするため以下をターミナルで実行する

$ export AWS_ACCESS_KEY_ID=自分のbucketのACCESS_KEY_IDを入れる
$ export AWS_SECRET_ACCESS_KEY=自分のbucketのSECRET_ACCESS_KEYを入れる

※以上の実装はAWSS3にbucketを作成してからでないとできないので注意。


不明点、修正点ございましたらコメントよろしくお願いします。