Active Record STI感到困惑

时间:2017-07-08 17:50:04

标签: ruby-on-rails ruby activerecord

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:单表继承机制   未能找到子类:&#39; FooSpec&#39;。提出此错误   因为列&#39;类型&#39;保留用于存储类的情况   遗产。如果您不打算将此列重命名,请重命名   用于存储继承类或覆盖   Spec.inheritance_column使用另一列来获取该信息。

有时我会从应用中获得稍微不同的错误,但我无法在控制台中重现它:

  

ActiveRecord :: SubclassNotFound(无效的单表继承类型:   FooSpec不是Spec的子类

嗯......正如您所看到的,FooSpec绝对是Spec的子类。这些错误通常意味着您使用type作为属性,并且没有告诉ActiveRecord它不是STI鉴别器。这不是这里的情况。想法?

1 个答案:

答案 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