Help us understand the problem. What is going on with this article?

[Rails] routingとmodelの命名規則が合わないときのaccepts_nested_attributes_forでハマる

accepts_nested_attributes_for とは?

Railsで一つのフォームを使って、関連性のある親子レコードを楽に保存できる、非常に便利なメソッドです。
ggるとすぐ出てくるのですが、あまり評判はよくありません。

が、いずれにしても便利であるがゆえにサラリと親子レコードを作りたいときなどは使いたくなるのも心情です。
(そしてその中で少しハマってしまったので残しておこうと思います。)

ここでは基本的な accepts_nested_attributes_for の使い方は割愛します。

揃っていないroutingとmodelの命名規則

一般的にaccepts_nested_attributes_forを使う場合、viewファイルでは

_form.html.erb
<%= form_with model: @parent do |f| %>
  <%= f.text_fields :name %>
  <%= f.fields_for :children do |ff| %>
    <%= ff.text_fields :name %>
  <% end %>
  <%= f.submit '作成する' %>
<% end %>

といった形でformを作ります。

が、今回はmodelとroutingの命名が違うという状況だったため、

# 利用したいmodel
class Parent

# Parentモデルを操作するroutes
resources :main

この状況で form_with model: @parent としてしまうと、
Railsの命名規則に則った形で処理しようとするため、Routing Errorとなります。

そういった場合、フォームを配置する際に、form_with url: main_path といった形でformの向き先をroutesに合った形で記載することになるのですが、

_form.html.erb
<%= form_with url: main_path, scope: :parent %>

としてしまったがばっかりに、formから渡されるデータ形式が合わずに、変にハマることになりました。

form_with model: @parent で書いた場合

出力されるHTML
<input type="text" name="parent[children_attributes][0][name]">
params(抜粋)
"parent" => {
  "name"=>"hoge",
  "children_attributes"=>{
    "0" => {
      "name"=>"hoge"
    }
  }
}

form_with url: main_path, scope: :parent で書いた場合

出力されるHTML
<input type="text" name="parent[children][name]">
params(抜粋)
"parent" => {
  "children"=>{
    "name"=>"hoge"
  }
}

といった形で、受け渡しが大きく変わり、複数の子レコードを作れない状態になります。
(なんなら想定していた形式と違いすぎてStrong Parametersで弾かれます)

結論

routesとmodelの命名規則が合わない場合でaccepts_nested_attributes_forを利用する場合は、

_form.html.erb
<%= form_with model: @parent, url: main_path do |f| %>

modelを渡してあげるのが正解。

scopeで書いてしまうと、接頭語として使う文字列を指定するだけで、modelの階層構造なんてわからないので、当たり前といえば当たり前。

mcfish
metaps
世界の頭脳へ コンピュータにあらゆるデータを学習させて、人々の最適な意思決定を支える頭脳になることを目指しています。
https://metaps.com/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした