5
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

accepts_nested_attributes_forについて

Posted at

入力フォームを作成している際に、
関連するモデルも一緒に含めたフォームを作ることができるのか?
と疑問に思ったため、その方法について調べました。

この記事では、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

ここで子モデルのIngredientaccepts_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つを押さえることで、親モデルと子モデルを同時に扱うフォームを実装できます。
この記事が誰かのお役に立てれば幸いです。

5
1
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
5
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?