具有嵌套属性创建的模型会更改before_validation和before_save之间的关联类型属性

时间:2017-02-16 00:31:00

标签: ruby-on-rails activerecord single-table-inheritance

我有一个模型Guest,它采用Numberplate的嵌套属性。

Guest采用STI(单表继承)并继承自Person。为了防止需要额外查询或加入另一个表,我将人员类型保存在person_type表中名为Numberplate的字段中。这样,我知道客人拥有哪些Numberplates而无需加入人员表。

由于此设置,我需要在person_type上手动设置正确的Numberplate(还有其他人类型)。我在before_validation模型上将其实现为Numberplate回调:

before_validation do
    self.person_type = self.person.type
end

实际的实现有点通用,但归结为此。 现在我将在控制台的一个调用中创建一个GuestNumberplate,这一切都按预期工作:

Numberplate.new({person: Guest.new({company: Company.first}), plate: 'EFEF98'})

person_type实例上的Numberplate已正确设置为"Guest"

当我有一个API端点允许嵌套属性在一个请求中创建GuestNumberplate时,会出现问题。奇怪的是,person_type按预期存储为"Person'而不是"Guest"。我进行了一些调试,person_typebefore_validation回调中设置正确,但在该回调和before_save回调之间,person_type突然变为"Person"。 我试图覆盖person_type setter并在设置时记录。奇怪的是,在2个ActiveRecord回调之间没有调用setter。

我有点惊讶于这种行为是如何引入的,以及这是否是某个地方的Rails核心中的错误或者我没有考虑到什么。我目前的解决方法是将person_type设置为额外的before_save回调,但这不是最佳解决方案。

相关型号:

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

1 个答案:

答案 0 :(得分:0)

所以我想通了。

Person课程中我有这个:

has_many :numberplates, as: :person, inverse_of: :person

as: :person部分不应该出现并引入此行为。它是由于早期从多态性迁移到STI,因此是一个被遗忘的遗留物。一旦我删除了这一切,一切按预期工作。