概要
- 親子関係を持つモデルで、親ビューから子を複数表示・編集方法。
- 親子関係を持つモデルのStrongParameterの定義方法。
今後調査したい事
- ビュー側で+ボタンを押す度に動的に子の入力画面を増やしたり、ーボタンで減らしたりする
モデル
accepts_nested_attributes_forを利用することで、newやcreateするときに子のデータもまとめて設定できるようになります。
# アンケート(親)
# アンケートは質問(子)を複数持つ
class Enquate < ActiveRecord::Base
# attributes :id, :title,
has_many :questions
accepts_nested_attributes_for :questions
end
# 質問(子)
class Question < ActiveRecord::Base
# attributes :id, :content
belongs_to :enquate
end
コントローラ
has_manyでのオブジェクトの生成などはこちらも参考。
Railsドキュメント model
Railsガイド ActiveRecord Associations
StrongParameterにて、Enquateの内容に加えQuestionsの属性も許可するようにします。
ネストされたモデル(親子関係を持つモデル)でStrongParameterを利用する
class EnquatesController < ApplicationController
def new
@enquate = Enquate.new
# 入力用に空のオブジェクトを1つ生成します。
@enquate.questions.build
end
def create
@enquate = Enquate.new(enquate_params)
#...
end
def enuqate_params
params.require(:enquate).permit(:title, questions_attributes: [:id, :content])
end
end
ビュー
form_for @enquate do |f| f.fields_for :questionsを利用します。
fields_forにaccepts_nested_fields_for指定のある属性名を指定すると、自動的に子分のフィールドを作成し、name属性をenquate[questions_attribute[0]][content]のように展開してくれます。
= form_for @enquate do |f|
.field
= f.label :title
= f.text_field :title
.questions
= f.fields_for :questions do |q|
.field
# 例 <input id="enquate_questions_attributes_0_enquate_id" name="enquate[questions_attributes][0][enquate_id]" type="hidden" value="2" />
= q.hidden_field :enquate_id
.field
= q.label :content
# 例 <input id="enquate_questions_attributes_0_content" name="enquate[questions_attributes][0][content]" type="text" value="Test" />
= q.text_field:
子要素のキーが複合キーの場合
※ もし子要素の主キーが複合キーで、composite_primary_keysを利用している場合、:idではなく、:a_id, :b_idなど複合キーを明示しないと動作しないっぽい。(gemをいじったりする必要がでてしまう??)
= q.hidden_field :id # 値は"[1070, 190]"のように複合キーの配列の文字列になるけど、composite_primary_keys内で"[1070,190]"と比較されてたりして、うまく動作しない。
= q.hidden_field :a_id
= q.hidden_field :b_id
fields_forの参照元オブジェクトにアクセスするには
object属性を利用する.
= f.fields_for :questions do |q|
= q.object.id
fields_forの参照元オブジェクト(has_many時)のインデックスを取得するには
indexを利用する
= f.fields_for :questions do |q|
= q.object.id
= q.index
余談
- javascriptで、動的にQuestionの入力フィールドを増やしたい場合、HTMLのidやnameを知らずにrailsオブジェクトで行えるgemやメソッドってあるの?
- StrongParameter、ネストされたモデルの使い方、親子間のビューの使い方をざーっと眺めて、なんとなくRailsが使えるようになってきた気がする。