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

# 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

```ruby
<%= 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
```

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