LoginSignup
36
33

More than 3 years have passed since last update.

【Rails 6.0】 複数レコードの一括保存について

Posted at
1 / 2

はじめに

個人アプリで受発注管理機能を実装したので、その時に学んだ複数レコードの一括保存のやり方についてアウトプットします。

参考資料

今回の記事を作成するにあたり、以下の記事を大いに参考にさせていただきました。本当にありがとうございました。
【Rails 5】モデルを一括登録する手順
【Rails 6】form_with用いて一括登録する
1.2. 一括登録フォームの実装

制作物

商品登録.png

チェックボックスにチェックを入れた商品のみを登録する
商品保存.png

商品一覧.png

前提条件

Productモデル

Column Type
name string
price integer
unit string
availability boolean
models/product.rb
class Product < ApplicationRecord

  with_options presence: true do
   validates :name
   validates :unit
   validates :price, numericality: {only_integer: true, greater_than_or_equal_to: 0 }
   validates :availability, inclusion: { in: [true, false] }
  end

end

方針

  1. 複数商品を一括保存するためのコレクションモデルを作成
  2. コントローラーで、一括登録のための処理を記述
  3. ビュー画面で複数の商品を一括登録できるフォームを作成

1. 複数商品を一括保存するためのコレクションモデルを作成

modelsディレクトリの中にformディレクトリを作成し、その中にProductCollectionモデルとBaseモデルを作成します。

models/form/product_collection
class Form::ProductCollection < Form::Base
  FORM_COUNT = 10 #ここで、作成したい登録フォームの数を指定
  attr_accessor :products 

  def initialize(attributes = {})
    super attributes
    self.products = FORM_COUNT.times.map { Product.new() } unless self.products.present?
  end

  def products_attributes=(attributes)
    self.products = attributes.map { |_, v| Product.new(v) }
  end

  def save
    Product.transaction do
      self.products.map do |product|
        if product.availability # ここでチェックボックスにチェックを入れている商品のみが保存される
          product.save
        end
      end
    end
      return true
    rescue => e
      return false
  end
end

models/form/base.rb
class Form::Base
  include ActiveModel::Model
  include ActiveModel::Callbacks
  include ActiveModel::Validations
  include ActiveModel::Validations::Callbacks

end

2. コントローラーでインスタンスの生成および、データの処理

controllers/products_controller.rb

class ProductsController < ApplicationController

  def new
    @form = Form::ProductCollection.new
  end

  def create
    @form = Form::ProductCollection.new(product_collection_params)
    if @form.save
      redirect_to products_path, notice: "商品を登録しました"
    else
      flash.now[:alert] = "商品登録に失敗しました"
      render :new
    end

  end

  private

    def product_collection_params
        params.require(:form_product_collection)
        .permit(products_attributes: [:name, :price, :unit, :availability])
    end

end

@form = Form::ProductCollection.newにより、先ほど作ったモデルのインスタンスが生成されます。
ストロングパラメータはproducts_attributesで受け取ります。

3. ビュー画面で複数の商品を一括登録できるフォームを作成

views/products/new.html.haml
= form_with model: @form, url: products_path, method: :post, local: true do |form|
  %table
    %thread
      %tr
        %th 登録
        %th 商品名
        %th 販売価格(円)
        %th 発注単位
  %tbody
    = form.fields_for :products do |f|
      %tr
        %td.text-center
          = f.check_box :availability
        %td
          = f.text_field :name
        %td
          = f.text_field :price
        %td
          = f.text_field :unit
  = form.submit "一括登録"
  = link_to "戻る", :back

form_withとfields_forを使って複数登録できるフォームを作成しています。

これで、一括保存ができると思います。

最後に

ご覧いただきありがとうござました。何か間違いがあれば、ご指摘をお願いします。

36
33
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
36
33