accepts_nested_attributes_forの使い方
- 参考
- 何がしたいか
- モデルで accepts_nested_attributes_for を宣言
- form を作る
- view でネストするパラメータを作るための form を作成
- ストロングパラメータ
- save
- ポイント
- まとめ
参考
http://kzy52.com/entry/2013/07/10/200144
何がしたいか
form でネストする params を作って異なる model の属性を格納し、一回のアクションで同時にsaveしたい。
モデルで accepts_nested_attributes_for を宣言
ネストさせるパラメータの親のモデルクラスで accepts_nested_attributes_for を記述する。引数にはネストの子のモデルをシンボルで指定。
class Teacher < ApplicationRecord belongs_to :school accepts_nested_attributes_for :school end
accepts_nested_attributes_for メソッドを使う前にモデル同士のリレーションが宣言されている必要がある。
こうすることで school_attributes メソッドが teacher モデルに追加される。
form を作る
新しいインスタンスを同時に作る場合。
def new @teacher = Teacher.new @teacher.build_school end
これで @teacher と @teacher.school が同時に作られる。中身は空。
<%= render 'form', teacher: @teacher, school: @school %>
view でネストするパラメータを作るための form を作成
<%= form_with(model: teacher, local: true) do |form| %> <div class="field"> <%= form.label :name, '名前' %> <%= form.text_field :name %> </div> <%= form.fields_for :school do |school_form| %> <div class="field"> <%= school_form.label :name, '学校名' %> <%= school_form.text_field :name %> </div> <% end %> <div class="actions"> <%= form.submit %> </div> <% end %>
form_with 内で 子params のための fields_for の領域を作る。
上の例でいうと form.fields_for とすることで params がネストされる。
ストロングパラメータ
# teachers_controller.rb def teacher_params params.require(:teacher).permit(:name, school_attributes: [:name]) end
ここで school_attributes をpermit に加えると、コントローラで入れ子のschoolの属性を @teacher.school として扱えるようになる。
save
def create @teacher = Teacher.new(teacher_params) respond_to do |format| if @teacher.save reset_session session[:teacher] = @teacher.id format.html { redirect_to @teacher, notice: '登録が完了しました.' } format.json { render :show, status: :created, location: @teacher } else format.html { render :new } format.json { render json: @teacher.errors, status: :unprocessable_entity } end end end
あとは @teacher のみを普通に save するときと同じ。
ポイント
accepts_nested_attributes_for はモデル同士のリレーションを前提としている。ただし、 accepts_nested_attributes_for はネストさせる params の親のモデルクラスで宣言する。今回のようにモデル自体のリレーションの親子関係 (belongs_to, has_many)と params の親子関係が逆だとややこしいので注意する必要がある。
まとめ
上の二つでやろうとしていた処理が accepts_nested_attributes_for を使ったことで簡単に実装することができた!