LoginSignup
35
35

More than 3 years have passed since last update.

【Rails】cocoonを用いて親子孫関係のテーブルに複数のデータを同時保存する方法

Last updated at Posted at 2019-09-09

目的

gemのcocoonを使って親子孫関係のテーブルに複数のデータを同時に保存できるようにします
1つの送信ボタンで複数のモデルに保存できるため、非常に便利です
1つの投稿に対してカテゴリーやタグ付けをすることを考えるてください
そうすると、一回の投稿で複数のデータを投稿できた方がいいことがわかりますね

前提

今回の投稿ので使用するモデル、データベースについて説明します

モデルの関係

関係 モデル名
Parent
Child
Grandchild

上の表がモデル同士の関係になります
上の関係で実装を進めます

モデルとカラム

モデル名 カラム名
Parent p_name
Child c_name
Grandchild g_name

各テーブルにあるそれぞれのカラムの名前になります

実装方法

まず、gem cocoomインストール、モデル、コントローラーを作ります
その後、モデル、コントローラー、ビューの順番で説明します

準備

Gemfile

gemのcocoonを利用して実装するため、まずはインストールしていきます

Gemfile
gem cocoon
ターミナル
$ bundle install

モデル、コントローラー作成

ターミナル
$ rails g model Parent p_name:string
$ rails g model Child c_name:string parent_id:integer
$ rails g model Grandchild g_name:string child_id:integer
$ rails g controller parents new create
ターミナル
$ rails db:migrate

モデル

モデルの記述を説明していきます。

モデル作成

parent.rb
  has_many :children, dependent: :destroy
  accepts_nested_attributes_for :children, allow: true

アソシエーションは上で説明したように、
ParentはChildを複数持ってるため、has_manyで繋げます
accepts_nested_attributes_forはビューからデータを送る際に、
parentと一緒にchildを送るための記述です
詳しくはあとで説明します、、、

child.rb
  belongs_to :parent
  has_many :grandchildren, dependent: :destroy
  accepts_nested_attributes_for :grandchildren, allow: true
grandchild.rb
  belongs_to :child

child,grandchildparentと同じように記述します

コントローラー

コントローラーに以下の記述をします

parents_controller.rb
  def new
    @parent = Parent.new
    @children = @parent.children.build
    @grandchildren = @children.grandchildren.build
  end

  def create
    @parent = Parent.new(parent_params)
    @parent.save
  end

private
def parent_params
      params.require(:parent).permit(:p_name, children_attributes: [:id, :c_name, :_destroy, grandchildren_attributes: [:id, :g_name, :_destroy]])
end

new

@parent,@children,@grandchildrenをそれぞれ定義します

create

@parent = Parent.new(parent_params)でデータを作って、
@parent.savechild,grandchildにも同時に保存しています

ストロングパラメーター

accepts_nested_attributes_for

モデルで記述したaccepts_nested_attributes_forことで
params_attributes: []を一緒に追加して送ることができています。

ストロングパラメーターは
_attributes: []などの配列を一番後ろに書かないといけないので注意してください

ビュー

new.html.erb

new.html.erb
<%= form_with(model: @parent, local: true) do |s| %>
    <%= s.label :p_name %>
    <%= s.text_field :p_name %>
    <div class="parents">
        <%= s.fields_for :children do |t| %>
            <%= render "children_fields", f: t %>
        <% end %>
        <div class="links">
            <%= link_to_add_association "子供を追加", s, :children %>
        </div>
    </div>
    <div class="actions">
        <%= s.submit %>
    </div>
<% end %>

_children_fields.html.erb

_children_fields.html.erb
<div class="nested-fields">
    <%= f.label "c_name" %>
    <%= f.text_field :c_name %>
    <%= link_to_remove_association "remove child", f %>

    <%= f.fields_for :grandchildren do |u| %>
        <%= render "grandchild_fields", f: u %>
    <%end%>

    <%= link_to_add_association "孫を追加", f, :grandchildren %>
</div>

_grandchild_fields.html.erb

_grandchild_fields.html.erb
<div class="nested-fields">
    <%= f.text_field :g_name %>
    <%= link_to_remove_association "remove grandchild", f %>
</div>

部分テンプレートの名前に注意してください
名前が合っていないとrenderできなかったり、入力フォームを追加できません

おわりに

cocoonで入力フォームを増やせるととても便利ですね
様々な場面で応用できるので習得しましょう

質問、気になるところなどございましたらコメントよろしくお願いします

35
35
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
35
35