2017-07-08 67 views
1

STI不工作,因为我认为它应该在某些条件下。活跃记录STI困惑

的模型(简体):

class Order < ApplicationRecord 
    has_many :items, class_name: 'OrderItem', inverse_of: :order 
end 

class OrderItem < ApplicationRecord 
    belongs_to :order, inverse_of: :items 
    has_one :spec, inverse_of: :order_item 
end 

class Spec < ApplicationRecord 
    belongs_to :order_item, inverse_of: :spec 
end 

class FooSpec < Spec 
end 

class BarSpec < Spec 
end 

模式(简体):

create_table "specs", force: :cascade do |t| 
    t.string "type", null: false 
    t.bigint "order_item_id", null: false 
    ... 
end 

我使用ActiveRecord::Associations::Preloader避免我GraphQL服务器N + 1点的问题。我开始收到一些STI错误。

从一个控制台,这个工作正常,并返回一个FooSpecBarSpec

Order.includes(items: :spec).first.items.first.spec 

同样的,这样的:

Order.includes(:items).first.items.includes(:spec).first.spec 

这也太:

ActiveRecord::Associations::Preloader.new 
    .preload(Order.all, :items).first.owners.first.items.first.spec 

然而,这:

ActiveRecord::Associations::Preloader.new.preload(Order.all, items: :spec) 

而且这样的:

ActiveRecord::Associations::Preloader.new 
    .preload(Order.all.map{|o| o.items}.flatten, :spec) 

引发错误:

ActiveRecord::SubclassNotFound: The single-table inheritance mechanism failed to locate the subclass: 'FooSpec'. This error is raised because the column 'type' is reserved for storing the class in case of inheritance. Please rename this column if you didn't intend it to be used for storing the inheritance class or overwrite Spec.inheritance_column to use another column for that information.

有时候我会从应用程序得到一个稍微不同的错误,但我不能在控制台中重现:

ActiveRecord::SubclassNotFound (Invalid single-table inheritance type: FooSpec is not a subclass of Spec)

嗯...你可以看到,FooSpec绝对是的一个子类。这些错误通常意味着你使用了type作为属性,并没有告诉ActiveRecord它不是STI鉴别器。情况并非如此。想法?

回答

0

我发现了罪魁祸首。我有这样的:

class FooSpec < Spec 
    validates :my_field, inclusion: {in: MyClass::CHOICES} 
end 

当我把它改成这样,问题就消失了:

class FooSpec < Spec 
    validates :my_field, inclusion: {in: -> (_instance) {MyClass::CHOICES}} 
end 

我不明白为什么。 MyClass::CHOICES是一个包含数组的简单常量。该班级是classy_enum

class MyClass < MyClassyEnum 
    CHOICES = %w[ 
    choiceOne 
    choiceTwo 
    ].freeze 
    ... 
end