accepts_nested_attributes_for メソッドで苦労した点の記録です。表題の通り、ユーザーが何も入力しなかった場合に空のレコードができてしまうのを防ぐためのメソッドを探して実装した際の記録になります。
結論
:reject_if proc (もしくはlambda) を使う
起きていた現象
個人的にはとても便利な accepts_nested_attributes_for メソッドですが、前回の記事でも編集画面の不具合が出るのを修正したり、結構クセのあるメソッドだなという印象を受けています。
今回取り扱うのは、上にも書いた通り「ユーザーが何も入力しなかった場合に空のレコードが発生してしまう」というもの。といっても、何も入力しなけりゃそりゃ空のレコードができても仕方ないよ、と思ってしまうのですが、この状況を解消したいと思って調べてみました。
問題解決のためにやったこと
今回は大したことやっておらず、とりあえずRailsガイドで調べてみたこちらの記事を見つけました。
9.5 空のレコードができないようにする
ユーザーが何も入力しなかったフィールドを無視できれば何かと便利です。これは、:reject_if procをaccepts_nested_attributes_forに渡すことで制御できます。
早速使ってみます。
class User < ApplicationRecord
has_many :blogs, dependent: :destroy
accepts_nested_attributes_for :blogs, reject_if: proc {|attributes| attributes['title'].blank? and attributes['content'].blank? and attributes['blog_num'].blank?}, allow_destroy: true
end
確かに、これで編集画面で空のレコードが登録されてしまう不具合は出なくなりました。
一点気になるのが、Rails ガイドの解説文では :reject_if proc を使うと書いてあるのに、用例では :reject_if lambda を用いていました。
ユーザーが何も入力しなかったフィールドを無視できれば何かと便利です。これは、:reject_if procをaccepts_nested_attributes_forに渡すことで制御できます。このprocは、フォームから送信された属性のハッシュ1つ1つについて呼び出されます。このprocがfalseを返す場合、Active Recordはそのハッシュに関連付けられたオブジェクトを作成しません。以下の例では、kind属性が設定されている場合にのみ住所オブジェクトを生成します。
class Person < ApplicationRecord
has_many :addresses
accepts_nested_attributes_for :addresses, reject_if: lambda {|attributes| attributes['kind'].blank?}
end
proc でも lambda でも不具合は解消されましたが、2つがどう異なるのか現時点ではうまく説明できません。。。これも解決したら記事を更新しようと思っています。
今回の不具合も accepts_nested_attributes_for メソッド を使うと起こりがちらしいので、使う場合は気をつけたいと思います。