入力フォームを作成している際に、
関連するモデルも一緒に含めたフォームを作ることができるのか?
と疑問に思ったため、その方法について調べました。
この記事では、Rails の accepts_nested_attributes_for を用いて、
親モデルと関連モデルを同時に投稿するフォームの作成方法を紹介します。
今回の設定
まずは今回想定するwebアプリの簡単な設定を記述します
- 料理投稿機能を持つ
- RecipeモデルがIngredientモデルと1対多の関係にある(多対多でも可能
このような設定において、Recipeを投稿するフォームでIngredientも同時に登録できるようにしたいという状況を考えます。
具体的な実装方法
ではここから以上のような設定において関連モデルも含めたフォームの作成方法について紹介します。
accepts_nested_attributes_for
accepts_nested_attributes_forについてRailsガイドには以下のような説明があります。
モデルクラスのaccepts_nested_attributes_forメソッドによって、関連付けられているレコードの更新や破棄を行えるようになります。
今回の例では、Recipe モデルに以下のように記述します。
class Recipe < ApplicationRecord
has_many :ingredients, dependent: :destroy
accepts_nested_attributes_for :ingredients,
allow_destroy: true
end
ここで子モデルのIngredientをaccepts_nested_attributes_forで指定することで、Recipeモデルと共に更新や破棄ができるようになります。
コントローラーの設定
次にコントローラーの記述を説明します。
class RecipesController < ApplicationController
def new
@recipe = Recipe.new
@recipe.ingredients.build
end
def create
@recipe = Recipe.new(recipe_params)
if @recipe.save
redirect_to @recipe
else
render :new
end
end
private
def recipe_params
params.require(:recipe).permit(
:title,
ingredients_attributes: [:name, :quantity, :_destroy]
)
end
end
-
@recipe.ingredients.buildについて
これによって新規作成フォームにおいて材料の入力フォームを表示できるようになります。
@親名.子名s.buildといった記述になります。 -
ingredients_attributes: [:name, :quantity, :_destroy]について
許可するパラメータに子モデルのパラメータも許可する必要があります。
子名s_attributes: [:カラム名1, :カラム名2]といった記述になります。
フォームの設定
最後に関連モデルを含めたフォームの書き方を説明します。
<%= form_with model: @recipe do |f| %>
<div>
<%= f.label :title %>
<%= f.text_field :title %>
</div>
<h3>材料</h3>
<%= f.fields_for :ingredients do |ifield| %>
<div style="margin-bottom: 1rem;">
<%= ifield.label :name, "材料名" %>
<%= ifield.text_field :name %>
<%= ifield.label :quantity, "分量" %>
<%= ifield.text_field :quantity %>
</div>
<% end %>
<%= f.submit "レシピ作成" %>
<% end %>
- fields_forについて
これによって子モデルに対するフォームを作成できるようになります。
f.fields_for :子モデルs do |ブロック変数|といった形で使用します。
結論
accepts_nested_attributes_forを使用することで、
関連したモデルも含めたフォームを作成することができます。
- モデルで accepts_nested_attributes_for を設定する
- コントローラーで build と Strong Parameters を設定する
- フォームで fields_for を使う
以上の3つを押さえることで、親モデルと子モデルを同時に扱うフォームを実装できます。
この記事が誰かのお役に立てれば幸いです。