🙄

[Rails]CarrierWaveを使った画像アップロード

4 min read

CarrierWaveとは

  • Railsにおける画像アップロード用ライブラリ。
  • CarrierWaveの特徴として、Uploaderクラスを別に持つという点

Gemfileにcarrierwave追加

CarrierWaveを導入するためにGemfileに以下を追加します。

Gemfile
gem 'carrierwave', '~> 2.0'

そして、CarrierWaveをインストール

$ bundle install

アップローダークラスを作成

Carrierwaveをインストールすることで、以下のコマンドを使用できるようになります。

$ bundle exec rails generate uploader BoardImage

コマンドを実行すると、以下のapp/uploaders/board_image_uploader.rb が生成されます。

生成されたアップローダにデフォルト画像ファイルの設定と、アップロード可能な拡張子の設定を追記しておきましょう。

app/uploaders/board_image_uploader.rb
class BoardImageUploader < CarrierWave::Uploader::Base
  storage :file
  
  def store_dir
    "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
  end
  
  def default_url # デフォルトの画像ファイル
    'board_placeholder.png'
  end
  
  def extension_whitelist # 拡張子の制限
    %w[jpg jpeg gif png]
  end
  
end

画像のアップロード先を確認

app/uploaders/board_image_uploader.rb
storage :file

def store_dir
  "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
end

また、上記のコードより、デフォルトでstorage :file が指定されているので、アップロードしたファイルはpublic/ 配下に保存されます。

.gitignoreを編集

アップロードした画像をGit管理下から外すため、下記の追記をしましょう

.gitignore
/public/uploads

アップロード画像のカラムを追加

アップロード画像の情報を保存するboard_image カラムを追加するためにマイグレーションファイルを作成しましょう。

$ bundle exec rails g migration AddBoardImageToBoards board_image:string

作成されたマイグレーションファイルを確認しましょう

20210913013519_add_board_image_to_boards.rb
class AddBoardImageToBoards < ActiveRecord::Migration[5.2]
  def change
    add_column :boards, :board_image, :string
  end
end

マイグレーションを実行して、boardsテーブルにboard_image カラムを追加します。

$ bundle exec rails db:migrate

なお、DBに保存されるのは「画像データ」ではなく「画像のファイル名」です。

ファイル名えはなく画像データを保存するとDBサーバの容量を圧迫する。board_imageカラムには、どの画像ファイルか確認できるようにファイル名だけを保存し、画像を表示するときに「画像が格納されているパス」と「DBが保存されているファイル名」を使う

アップローダークラスとカラムの紐付け

次に「board_image カラム」と「BoardImageUploader クラス」を紐付けます。

app/models/board.rb
class Board < ApplicationRecord
  mount_uploader :board_image, BoardImageUploader
  belongs_to :user

  validates :title, presence: true, length: { maximum: 255 }
  validates :body, presence: true, length: { maximum: 65_535 }
end

ストロングパラメータに追記する

画像ファイルをコントローラで受けtるけるようにストロングパラメータに追記する

app/controllers/boards_controller.rb
def board_params
    params.require(:board).permit(:title, :body, :board_image, :board_image_cache)
  end

画像ファイルの入力フィールドを用意する

app/boards/_form.html.erb
<%= form_with model:board,  local: true do |f| %>
<%= render 'shared/error_messages', object: f.object %>
        <div class="form-group">
          <%= f.label :title %>
          <%= f.text_field :title, class: 'form-control' %>
        </div>
        <div class="form-group">
          <%= f.label :body %>
          <%= f.text_area :body, class: 'form-control', rows: 10 %>
        </div>
        <div class="form-group">
          <%= f.label :board_image %>
          <%= f.file_field :board_image, class: 'form-control mb-3', accept: 'image/*' %>
          <%= f.hidden_field :board_image_cache %>
        </div>
        <div class="mt-3 mb-3">
					#  以下はプレビュー画面を表示するコード
          <%= image_tag board.board_image.url,
                        id: 'preview',
                        size: '300x200' %>
        </div>

        <%= f.submit class: 'btn btn-primary' %>
      <% end %>

JavaScriptでプレビュー機能を作成する

_form.html.erbのコードと連動し、プレビュー画面をJavaScriptで作成する

assets/javascripts/common.js
function previewImage() {
    const target = this.event.target;
    const file = target.files[0];
    const reader  = new FileReader();
    reader.onloadend = function () {
        const preview = document.querySelector("#preview")
        if(preview) {
            preview.src = reader.result;
        }
    }
    if (file) {
        reader.readAsDataURL(file);
    }
  }

アップロードした画像を表示

app/views/boards/_board.html
<%= image_tag board.board_image.url, class: 'card-img-top', size: '300x200' %>

日本語化する

config/locales/activerecord/ja.yml
ja:
  activerecord:
    attributes:
      board:
        title: 'タイトル'
        body: '本文'
        board_image: 'サムネイル'

こちらからコピーしてconfig/locales/carrierwave/ja.yml ファイルを作る

carrierwave-i18n/ja.yml at master · carrierwaveuploader/carrierwave-i18n

参考文献

CarrierWaveチュートリアル

Discussion

ログインするとコメントできます