#目的
gemのcocoonを使って親子孫関係のテーブルに複数のデータを同時に保存できるようにします
1つの送信ボタンで複数のモデルに保存できるため、非常に便利です
1つの投稿に対してカテゴリーやタグ付けをすることを考えるてください
そうすると、一回の投稿で複数のデータを投稿できた方がいいことがわかりますね
#前提
今回の投稿ので使用するモデル、データベースについて説明します
##モデルの関係
関係 | モデル名 |
---|---|
親 | Parent |
子 | Child |
孫 | Grandchild |
上の表がモデル同士の関係になります | |
上の関係で実装を進めます | |
##モデルとカラム | |
モデル名 | カラム名 |
:-: | :-: |
Parent | p_name |
Child | c_name |
Grandchild | g_name |
各テーブルにあるそれぞれのカラムの名前になります |
#実装方法
まず、gem cocoomインストール、モデル、コントローラーを作ります
その後、モデル、コントローラー、ビューの順番で説明します
##準備
###Gemfile
gemのcocoonを利用して実装するため、まずはインストールしていきます
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
##モデル
モデルの記述を説明していきます。
###モデル作成
has_many :children, dependent: :destroy
accepts_nested_attributes_for :children, allow: true
アソシエーションは上で説明したように、
ParentはChildを複数持ってるため、has_many
で繋げます
accepts_nested_attributes_for
はビューからデータを送る際に、
parent
と一緒にchild
を送るための記述です
詳しくはあとで説明します、、、
belongs_to :parent
has_many :grandchildren, dependent: :destroy
accepts_nested_attributes_for :grandchildren, allow: true
belongs_to :child
child
,grandchild
もparent
と同じように記述します
##コントローラー
コントローラーに以下の記述をします
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.save
でchild
,grandchild
にも同時に保存しています
###ストロングパラメーター
####accepts_nested_attributes_for
モデルで記述したaccepts_nested_attributes_for
ことで
params
に_attributes: []
を一緒に追加して送ることができています。
ストロングパラメーターは
_attributes: []
などの配列を一番後ろに書かないといけないので注意してください
##ビュー
###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
<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
<div class="nested-fields">
<%= f.text_field :g_name %>
<%= link_to_remove_association "remove grandchild", f %>
</div>
部分テンプレートの名前に注意してください
名前が合っていないとrenderできなかったり、入力フォームを追加できません
#おわりに
cocoonで入力フォームを増やせるととても便利ですね
様々な場面で応用できるので習得しましょう
###質問、気になるところなどございましたらコメントよろしくお願いします