執筆中
概要
carrierwaveとcocoonを使った複数枚画像投稿機能。
結論から言うと、本体とは別に画像テーブルを作成し、formをcocoonで複製しないと、ハッシュ化した複数投稿はできない。(と、思う。)
いろいろな記事があるが、画像の名前をハッシュ化していなかったりとピンとくる記事がなかったのでそれらを補ったものを投稿する。
開発環境
・Ruby: 3.1.2
・Rails: 7.0.2
・OS: macOS Monterey
準備
テーブル構成
本が1に対して、画像が多のテーブル構造。
carrierwaveの公式サイトでは複数画像の時は、json形式のカラムを作り(本記事だとbook)、そこに配列形式で格納する方法が紹介されているが、この方法で実装するとファイル名のハッシュ化で詰む。(後の、画像テーブルは別で用意するにて詳述する)
# images
lass CreateNoticeImages < ActiveRecord::Migration[7.0]
def change
create_table :images, comment: '投稿画像' do |t|
t.references :book, comment: '本', null: false, foreign_key: true
t.text :content, comment: 'コンテント'
t.timestamps
end
end
end
# book
class CreateBooks < ActiveRecord::Migration[7.0]
def change
create_table :books, comment: '本' do |t|
t.string :title, comment: 'タイトル', null: false
t.text :body, comment: '本文'
t.timestamps
end
end
end
gem追加
gem 'carrierwave'
gem 'cocoon'
gem 'mini_magick'
uploaderクラスの追加
rails g uploader image
CarrierWave編集
ApplicationUploaderクラス
# frozen_string_literal: true
class ApplicationUploader < CarrierWave::Uploader::Base
storage Settings.use_gcs ? :fog : :file
# see CarrierWave::Uploader::Configuration#add_config
def self.fog_public
true
end
def extension_allowlist
%w[jpg jpeg gif png pdf]
end
def content_type_allowlist
%w[image/jpeg image/gif image/png application/pdf]
end
def store_dir
"uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
end
# このメソッドで画像名をハッシュ化してる。ここ大事。
def filename
"#{secure_token}.#{file.extension}" if file
end
def fog_directory
if fog_public
super
else
Settings.fog_directory_private
end
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
ImageUploaderクラス
# frozen_string_literal: true
class ImageUploader < ApplicationUploader
include CarrierWave::MiniMagick
# override allowlist in ApplicationUploader
def extension_allowlist
%w[jpg jpeg gif png]
end
def content_type_allowlist
%w[image/jpeg image/gif image/png]
end
# ここでサムネイル画像のサイズ指定してる。
# image_tagで使いたかったら、.thumb.url のように指定する。
version :thumb do
process resize_to_fit: [300, 200]
end
class << self
def accept_mimetypes
new.content_type_allowlist.join(',')
end
end
end