はじめに
掲示板に画像投稿機能を実装しましょう。今回は投稿前に画像表示するプレビュー機能も実装します。
CarrierWaveとは
- Railsにおける画像アップロード用ライブラリ。
- CarrierWaveの特徴として、Uploaderクラスを別に持つという点。
作業の流れ
- carrierwaveのインストール
- アップローダークラスを作成
- アップロード画像のカラムを追加
- アップローダークラスとカラムの紐付け
- ストロングパラメータに追記する
- 画像ファイルの入力フィールドを用意する
- JavaScriptでプレビュー機能を作成する
- アップロードした画像を表示
- 日本語化する
carrierwaveのインストール
CarrierWaveを導入するためにGemfile
に以下を追加します。
gem 'carrierwave', '~> 2.0'
そして、CarrierWaveをインストール
$ bundle install
アップローダークラスを作成
Carrierwaveをインストールすることで、以下のコマンドを使用できるようになります。
$ bundle exec rails generate uploader BoardImage
コマンドを実行すると、以下の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
画像のアップロード先を確認
storage :file
def store_dir
"uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
end
また、上記のコードより、デフォルトでstorage :file
が指定されているので、アップロードしたファイルはpublic/
配下に保存されます。
.gitignoreを編集
アップロードした画像をGit管理下から外すため、下記の追記をしましょう
/public/uploads
アップロード画像のカラムを追加
アップロード画像の情報を保存するboard_image
カラムを追加するためにマイグレーションファイルを作成しましょう。
$ bundle exec rails g migration AddBoardImageToBoards board_image:string
作成されたマイグレーションファイルを確認しましょう
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
クラス」を紐付けます。
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
ストロングパラメータに追記する
画像ファイルをコントローラで受けとれるようにストロングパラメータに追記する
def board_params
params.require(:board).permit(:title, :body, :board_image, :board_image_cache)
end
画像ファイルの入力フィールドを用意する
<%= 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/*', onchange: 'previewImage(preview)' %>
<%= 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で作成します。
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);
}
}
アップロードした画像を表示
<%= image_tag board.board_image.url, class: 'card-img-top', size: '300x200' %>
日本語化する
ロケールファイルに追記しましょう。
ja:
activerecord:
attributes:
board:
title: 'タイトル'
body: '本文'
board_image: 'サムネイル'
こちらからコピーしてconfig/locales/carrierwave/ja.yml
ファイルを作る
終わりに
忘れそうになったら、都度復習が必要ですね。
参考記事

コメント