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错误。
在控制台中,这样可以正常工作并返回FooSpec
或BarSpec
:
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:单表继承机制 未能找到子类:&#39; FooSpec&#39;。提出此错误 因为列&#39;类型&#39;保留用于存储类的情况 遗产。如果您不打算将此列重命名,请重命名 用于存储继承类或覆盖 Spec.inheritance_column使用另一列来获取该信息。
有时我会从应用中获得稍微不同的错误,但我无法在控制台中重现它:
ActiveRecord :: SubclassNotFound(无效的单表继承类型: FooSpec不是Spec的子类
嗯......正如您所看到的,FooSpec
绝对是Spec
的子类。这些错误通常意味着您使用type
作为属性,并且没有告诉ActiveRecord它不是STI鉴别器。这不是这里的情况。想法?
答案 0 :(得分: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