34
36

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 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で入力フォームを増やせるととても便利ですね
様々な場面で応用できるので習得しましょう

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

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

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?