LoginSignup
2
1

More than 3 years have passed since last update.

【サンプルアプリ作成】accepts_nested_attributes_forを使ったRailsの複数の子レコード同時作成、同時更新(Not gem)

Last updated at Posted at 2019-11-14

accepts_nested_attributes_forを使った複数の子レコード同時作成、同時更新モッグを作る

手順

  1. Rails新規アプリ作成
  2. rails g scaffoldで親と子を作る
  3. アソシエーション(accepts_nested_attributes_for)
  4. view修正(fields_for)
  5. controller実装(attributes)
  6. 完成

rails新規アプリ作成

今回は一行のコマンドでrails newからdb:createまでやりたいと思います。
railsのバージョンは5.2.3でデータペースはpostgresqlを使用します。

rails _5.2.3_ new sample-app -d postgresql && cd sample-app && bundle install --path vendor/bundle && rails db:create

rails g scaffoldで親と子を作る

まずはscaffoldで不要ファイルが生成されないように設定を書きます。

/config/application.rb
require_relative 'boot'

require 'rails/all'

# Require the gems listed in Gemfile, including any gems
# you've limited to :test, :development, or :production.
Bundler.require(*Rails.groups)

module SampleApp
  class Application < Rails::Application

## ここから追加

    config.generators do |g|
      g.javascripts false
      g.helper false
      g.test_framework false
    end

## ここまで

  end
end

これも一行で親と子のDBを作っちゃいます。

$ rails g scaffold parent name:string age:integer && rails g model child name:string age:integer parent_id:integer && rails db:migrate

アソシエーション

それぞれのmodelにアソシエーションを追加して


parent.rb
class Parent < ApplicationRecord
  has_many :childs
  accepts_nested_attributes_for :childs, reject_if: :reject_blank_child, allow_destroy: true

  def reject_blank_child(attributes)
    exists = attributes[:id].present?
    empty = attributes[:name].blank?
    attributes.merge!(_destroy: 1) if exists && empty
    !exists && empty
  end
end

child.rb
class Child < ApplicationRecord
  belongs_to :parent ,optional: true
end

view修正(fields_for)

views/parents/_form.html.erb

<%= form_for(parent) do |form| %>
  <% if parent.errors.any? %>
    <div id="error_explanation">
      <h2><%= pluralize(parent.errors.count, "error") %> prohibited this parent from being saved:</h2>
      <ul>
      <% parent.errors.full_messages.each do |message| %>
        <li><%= message %></li>
      <% end %>
      </ul>
    </div>
  <% end %>

  <div class="field">
    <%= form.label :parent_name %>
    <%= form.text_field :name %>
  </div>

  <div class="field">
    <%= form.label :parent_name %>
    <%= form.number_field :age %>
  </div>

## ここから追加

  <hr>
  <% n = 0 %>
  <%= form.fields_for :childs do |f| %>
    <%= "子供数#{n += 1}" %>

    <div class="field">
      <%= f.label :child_name %>
      <%= f.text_field :name %>
    </div>

    <div class="field">
      <%= f.label :child_age %>
      <%= f.number_field :age %>
    </div>
  <% end %>

## ここまで

  <div class="actions">
    <%= form.submit %>
  </div>
<% end %>

controller実装

app/controllers/properties_controller.rb
class ParentsController < ApplicationController
  before_action :set_parent, only: [:show, :edit, :update, :destroy]

  def index
    @parents = Parent.all
  end

  def show
  end

  def new
    @parent = Parent.new
    5.times { @parent.childs.build }                      ##追記
  end

  def edit
  end

  def create
    @parent = Parent.new(parent_params)

    respond_to do |format|
      if @parent.save
        format.html { redirect_to @parent, notice: 'parent was successfully created.' }
        format.json { render :show, status: :created, location: @parent }
      else
        format.html { render :new }
        format.json { render json: @parent.errors, status: :unprocessable_entity }
      end
    end
  end

  def update
    respond_to do |format|
      if @parent.update(parent_params)
        format.html { redirect_to @parent, notice: 'parent was successfully updated.' }
        format.json { render :show, status: :ok, location: @parent }
      else
        format.html { render :edit }
        format.json { render json: @parent.errors, status: :unprocessable_entity }
      end
    end
  end

  def destroy
    @parent.destroy
    respond_to do |format|
      format.html { redirect_to properties_url, notice: 'parent was successfully destroyed.' }
      format.json { head :no_content }
    end
  end

  private
    def set_parent
      @parent = parent.find(params[:id])
    end

    def parent_params
      params.require(:parent).permit(:name, :age, childs_attributes: [:name, :age, :_destroy, :id])  ##修正
    end
end
$ rails db:migrate && rails s

以上です!お疲れ様でした!

2
1
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
2
1