【Rails】親子孫関係にあるテーブルを一度に保存する
はじめに
例えばアンケートを作れるアプリを作成するとします。
その時、アンケートテーブル、質問テーブル、選択肢テーブルを設計したとします。
アンケートには複数個の質問があって、その質問単位に、複数個の選択肢があります。
アンケートと質問がネスト、質問と選択肢がネストして、3階層になっているイメージです。
モデル作成
まず、モデルクラスを作成します。
アンケートは複数の質問を持っている、質問は複数の選択肢を持っている状態をアソシエーションで表します。
# アンケートモデル
class Survey < ApplicationRecord
has_many :questions
accepts_nested_attributes_for :questions
end
# 質問モデル
class Question < ApplicationRecord
belongs_to :survey
has_many :options
accepts_nested_attributes_for :options
end
# 選択肢モデル
class Option < ApplicationRecord
belongs_to :question
end
accepts_nested_attributes_forを定義する
親子関係にあるテーブルを1つのフォームから保存する場合、accepts_nested_attributes_for
を定義します。
今回は親子孫まで3代のテーブルを保存したいため、親には子に対して、子には孫に対してのaccepts_nested_attributes_for
を定義しています。
コントローラ作成
次に、コントローラを作成します。
class SurveysController < ApplicationController
def new
@survey = Survey.new
questions = @survey.questions.build
questions.options.build
end
def create
survey = Survey.new(servey_params)
if survey.valid?
survey.save!
else
render :new
end
end
private
def servey_params
params.require(:survey).permit(:title, :description,
questions_attributes: [:text, :description,
options_attributes: [:text]
]
)
end
end
newアクション
新規アンケートの作成を考えて、newアクションを作っていきます。
(設問は自由に増減できることが望ましいですが、今回は親子孫テーブルを同時保存することを目的に書いていますので、1つのアンケートに設問、選択肢は1つずつとします)
この時、親モデルをインスタンス化すると共に、子モデル、孫モデルもインスタンス化しておきます。
でないと、フォームが描画されません。
ストロングパラメータ
モデルにaccepts_nested_attributes_for
を定義してあることで、POSTパラメタ(params)がネストして渡ってきます。
そのためストロングパラメータもネストさせます。
子孫モデルのパラメタは_attributes
を付けて、子孫モデルの各カラムに紐づくパラメタは配列にします。
子孫モデルは複数個入力される前提なので、paramsも配列で渡ってくるためです。
ビュー作成
いよいよビューを作成します。
<%= form_with model: @survey do |f| %>
<%= f.label :title %>
<%= f.text_field :title %>
<%= f.label :description %>
<%= f.text_area :description %>
<%= f.fields_for :questions do |qu| %>
<%= qu.label :text %>
<%= qu.text_field :text %>
<%= qu.label :description %>
<%= qu.text_area :description %>
<%= qu.fields_for :options do |op| %>
<%= op.label :text %>
<%= op.text_area :text %>
<% end %>
<% end %>
<%= f.submit 'send' %>
<% end %>
fields_for
フォームを書くときに、子孫モデルはfields_for
を使って繰り返し描画されるようにします。
その際、親モデルのメソッドとして書くことで、親に紐づいてPOSTされます。
今回は子孫モデルまであるので、孫モデルは子モデルにネストさせて書いています。
最後に
これでsubmit
するとcreateアクションに飛んでくるのでストロングパラメータを使ってモデルインスタンスを作り、saveすることで保存されます。
ディスカッション
コメント一覧
まだ、コメントがありません