2017-07-08 71 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