LoginSignup
12
18

More than 5 years have passed since last update.

1つの親レコードに対して複数の子レコードである画像をアップロードしたい。

Posted at

5日間くらい詰まって進まなかったので、同じところで詰まる人がいないようメモ

やりたいこと

フリマアプリのように、出品するアイテムに複数の画像をアップロードする機能を作りたい。

環境

Rails 5.0.7.1

使用するgem

  • carrierwave
  • mini_magick

手順

  1. gemをGemfileに記述し、bundle install
  2. モデル作成
  3. アップロードのためのviewを作成
  4. コントローラー作成

以上で完成!
手順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

以上で完成。

参考記事
CarrierWave Upload Multiple Images [2018 Update]

12
18
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
12
18