5日間くらい詰まって進まなかったので、同じところで詰まる人がいないようメモ
やりたいこと
フリマアプリのように、出品するアイテムに複数の画像をアップロードする機能を作りたい。
環境
Rails 5.0.7.1
使用するgem
- carrierwave
- mini_magick
手順
- gemをGemfileに記述し、bundle install
- モデル作成
- アップロードのためのviewを作成
- コントローラー作成
以上で完成!
手順2から解説
Model作成
コンソールでモデル作成
rails g model Product
rails g model Item_image
マイグレーションファイルにカラムの記述を行う
create_products.rb
class CreateProducts < ActiveRecord::Migration[5.0]
def change
create_table :products do |t|
t.string :name, null: false, default: ""
t.references :user, foreign_key: true
t.timestamps null: false, foreign_key: true
end
end
end
create_item__images.rb
class CreateItemImages < ActiveRecord::Migration[5.0]
def change
create_table :item_images do |t|
t.string :name, null: false, default: ""
t.references :product, foreign_key: true
t.timestamps
end
end
end
rake db:migrate
各モデルにアソシエーションを記述
product.rb
accepts_nested_attributes_forと記述することで、親レコードの作成と共に子レコードの作成が可能となる。
class Product < ApplicationRecord
has_many :item_images, :dependent => :destroy
accepts_nested_attributes_for :item_images, allow_destroy: true
end
item_image.rb
uploaderをマウントするコードを記述
class ItemImage < ApplicationRecord
mount_uploader :name, ImageUploader
belongs_to :product, optional: true
end
View作成
view側でアップローダーを作成する。
1つのアップローダーで画像の複数選択を出来るようにするためには、multiple: trueを記述する必要がある。
multiple: trueを記述した場合、paramsには配列として渡されるので、コントローラー側で配列の中身を取り出す処理が必要になる。
= f.fields_for :item_images do |i|
= i.file_field :name, multiple: true, type: 'file', name: "item_images[name][]"
Controller作成
ストロングパラメーターの記述
private
def product_params
params.require(:product).permit(
:name,
item_images_attributes: [:name])
end
newアクションでインスタンス生成し、createアクションで保存の処理を行う。
この際、params[:item_images]['name']の中身は配列なので、それぞれ@item_images取り出す処理を行う。
def new
@product = Product.new
@item_image = @product.item_images.build
end
def create
@product = Product.new(product_params)
if @product.save
binding.pry
params[:item_images]['name'].each do |a|
@item_image = @product.item_images.create!(name: a)
end
redirect_to root_path, notice: '出品しました。'
else
render :new
end
end
以上で完成。