具有嵌套属性创建的模型更改 before_validation 和 before_save 之间的关联类型属性
Model with nested attribute creation changes association type attribute between before_validation and before_save
我有一个模型 Guest
,它采用 Numberplate
的嵌套属性。
Guest
采用STI(单table继承)继承自Person
。为了防止需要额外查询或加入另一个 table,我将人员类型保存在 Numberplate
table 中名为 person_type
的字段中。这样,我就知道哪些车牌号属于客人,而不需要加入 table。
由于此设置,我需要在 Numberplate
上手动设置正确的 person_type
(还有另一种人类型)。我将其实现为 Numberplate
模型上的 before_validation
回调:
before_validation do
self.person_type = self.person.type
end
实际实现有点通用,但归结为这一点。
现在我将在控制台的一次调用中创建一个 Guest
和 Numberplate
这一切都按预期工作:
Numberplate.new({person: Guest.new({company: Company.first}), plate: 'EFEF98'})
Numberplate
实例上的 person_type
正确设置为 "Guest"
。
当我有一个允许嵌套属性在一个请求中创建 Guest
和 Numberplate
的 API 端点时,问题就出现了。奇怪的是 person_type
被存储为 "Person'
而不是预期的 "Guest"
。我调试了一下,person_type
在 before_validation
回调中设置正确,但在该回调和 before_save
回调之间 person_type
突然更改为 "Person"
。
我试图覆盖 person_type
setter 并在设置时记录。奇怪的是 setter 在 2 个 ActiveRecord 回调之间没有被调用。
对于这种行为是如何引入的,以及这是否是 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
所以我想通了。
在 Person
class 我有这个:
has_many :numberplates, as: :person, inverse_of: :person
as: :person
部分不应该存在并引入了此行为。它存在于早期从多态性到 STI 的迁移,因此被遗忘了。一旦我删除它,一切都按预期工作。
我有一个模型 Guest
,它采用 Numberplate
的嵌套属性。
Guest
采用STI(单table继承)继承自Person
。为了防止需要额外查询或加入另一个 table,我将人员类型保存在 Numberplate
table 中名为 person_type
的字段中。这样,我就知道哪些车牌号属于客人,而不需要加入 table。
由于此设置,我需要在 Numberplate
上手动设置正确的 person_type
(还有另一种人类型)。我将其实现为 Numberplate
模型上的 before_validation
回调:
before_validation do
self.person_type = self.person.type
end
实际实现有点通用,但归结为这一点。
现在我将在控制台的一次调用中创建一个 Guest
和 Numberplate
这一切都按预期工作:
Numberplate.new({person: Guest.new({company: Company.first}), plate: 'EFEF98'})
Numberplate
实例上的 person_type
正确设置为 "Guest"
。
当我有一个允许嵌套属性在一个请求中创建 Guest
和 Numberplate
的 API 端点时,问题就出现了。奇怪的是 person_type
被存储为 "Person'
而不是预期的 "Guest"
。我调试了一下,person_type
在 before_validation
回调中设置正确,但在该回调和 before_save
回调之间 person_type
突然更改为 "Person"
。
我试图覆盖 person_type
setter 并在设置时记录。奇怪的是 setter 在 2 个 ActiveRecord 回调之间没有被调用。
对于这种行为是如何引入的,以及这是否是 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
所以我想通了。
在 Person
class 我有这个:
has_many :numberplates, as: :person, inverse_of: :person
as: :person
部分不应该存在并引入了此行为。它存在于早期从多态性到 STI 的迁移,因此被遗忘了。一旦我删除它,一切都按预期工作。