Numberplate
のネストされた属性を持つGuest
というモデルがあります。ネストされた属性の作成を伴うモデルは、before_validationとbefore_saveの間のアソシエーションタイプ属性を変更します。
Guest
は、STI(単一テーブル継承)を採用し、Person
から継承します。余分なクエリや他のテーブルへの参加を避けるために、テーブルのperson_type
というフィールドに人のタイプを保存します。そうすれば、私はどのナンバープレートが、人テーブルに参加する必要なく、ゲストによって所有されているのか知ることができます。
この設定のため、Numberplate
(別の人物タイプがあります)に正しいperson_type
を手動で設定する必要があります。実際の実装はもう少し汎用的であるが、それはこれに沸く
before_validation do
self.person_type = self.person.type
end
:私はNumberplate
モデルにbefore_validation
コールバックとしてこれを実装しました。 予想通り今私は、コンソールでこのすべての作品を1回の呼び出しでGuest
とNumberplate
を作成します。
Numberplate.new({person: Guest.new({company: Company.first}), plate: 'EFEF98'})
person_type
をNumberplate
インスタンス上では正しく"Guest"
に設定されています。
ネストされた属性でGuest
とNumberplate
を1回のリクエストで作成できるAPIエンドポイントがある場合、問題が発生します。奇妙なことは、person_type
が"Person'
として格納され、期待通りには"Guest"
ではないということです。私はちょっとデバッグし、person_type
はbefore_validation
コールバックで正しく設定されますが、そのコールバックとbefore_save
コールバックの間でが突然"Person"
に変更されました。 私はperson_type
セッターを無効にしようとしました。奇妙なことは、2人のActiveRecordコールバックの間にsetterが呼び出されないということです。
この動作がどのように導入されたのか、これがRailsコアのどこかのバグか、何かを考慮していないかどうか少し気が散っています。私の現在の回避策は、before_save
コールバックでperson_type
を設定することですが、これは最適な解決策ではありません。
関連モデル:
class Guest < Person
accepts_nested_attributes_for :numberplates
end
class Numberplate < ApplicationRecord
before_validation do
self.person_type = self.person.type
end
after_validation do
# person_type is correctly set to "Guest"
puts self.inspect
end
before_create do
# person_type is now suddenly set to "Person"
puts self.inspect
end
end
[アソシエーションコールバック](http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html#module-ActiveRecord::Associations::ClassMethods-label-Association+callbacks)を試してください。 – max
@maxが試しただけで、同じ振る舞いを表示します – edwardmp
私の側にカスタムコードがなくても、person_type列をPersonに設定しているものがあります。奇妙な。 – edwardmp