使用 STI,对临时子类的第一次读取失败,但后续读取有效

Using STI, the first read for an interim subclass is failing but subsequent reads work

我有 Rails 4.2 模型使用 STI,它在第一次尝试读取记录时失败,但在以后的情况下成功。记录的类型是 KbtPrimary,它继承自 KbTagged,它继承自 Keybox。我需要在 KbTagged 上搜索,但在第一次读取 KbTagged 时找不到记录。发现第一个读取的是Keybox还是KbtPrimary。

经过简化,代码如下所示:

class Keybox < ActiveRecord::Base
  belongs_to :company
  acts_as_tenant :company
end
class KbTagged < Keybox; end
class KbtPrimary < KbTagged; end
box = KbTagged.where(name: 'Automated').first
puts box.blank? ? "Box:nil;" : "Box:#{box.name};"
box = Keybox.where(name: 'Automated').first
puts box.blank? ? "Box:nil;" : "Box:#{box.name};"
box = KbTagged.where(name: 'Automated').first
puts box.blank? ? "Box:nil;" : "Box:#{box.name};"

输出是这样的:

Box:nil;
Box:Automated;
Box:Automated;

如果先使用KbtPrimary或​​Keybox,则输出正确:

box = KbtPrimary.where(name: 'Automated').first
puts box.blank? ? "Box:nil;" : "Box:#{box.name};"
box = Keybox.where(name: 'Automated').first
puts box.blank? ? "Box:nil;" : "Box:#{box.name};"
box = KbtPrimary.where(name: 'Automated').first
puts box.blank? ? "Box:nil;" : "Box:#{box.name};"

输出:

Box:Automated;
Box:Automated;
Box:Automated;

SQL 第一次失败读取:

"SELECT "keyboxes".* FROM "keyboxes" WHERE "keyboxes"."type" IN ('KbTagged') AND "keyboxes"."company_id" = 2 AND "keyboxes"."name" = 'Automated'"

进一步编辑 SQL:

class Keybox < ActiveRecord::Base
  belongs_to :company
  acts_as_tenant :company
end
class KbTagged < Keybox; end
class KbtPrimary < KbTagged; end
puts KbTagged.where(name: 'Automated').to_sql
box = KbTagged.where(name: 'Automated').first
puts box.blank? ? "Box:nil;" : "Box:#{box.name};"
puts Keybox.where(name: 'Automated').to_sql
box = Keybox.where(name: 'Automated').first
puts box.blank? ? "Box:nil;" : "Box:#{box.name};"
puts KbTagged.where(name: 'Automated').to_sql
box = KbTagged.where(name: 'Automated').first
puts box.blank? ? "Box:nil;" : "Box:#{box.name};"

SELECT "keyboxes".* FROM "keyboxes" WHERE "keyboxes"."type" IN ('KbTagged') AND "keyboxes"."company_id" = 2 AND "keyboxes"."name" = 'Automated'
Box:nil;
SELECT "keyboxes".* FROM "keyboxes" WHERE "keyboxes"."company_id" = 2 AND "keyboxes"."name" = 'Automated'
Box:Automated;
SELECT "keyboxes".* FROM "keyboxes" WHERE "keyboxes"."type" IN ('KbTagged', 'KbtPrimary') AND "keyboxes"."company_id" = 2 AND "keyboxes"."name" = 'Automated'
Box:Automated;

问题出在 config/environments/development.rb 中,设置为:

# Do not eager load code on boot.
config.eager_load = false

将此设置为 true 会导致读取工作。但是,这在开发环境中并不是真正有益的。如果您有更好的解决方案,我将继续寻找更优的解决方案。

编辑: 我目前正在 app/config/initializers 中对 STI 类 发出要求来完成此操作,而不是在整个应用程序中强制使用 eager_load。至此,我相信影响会是那些类不会动态更新,需要重启服务器才能实现。我确实注意到有一个 gem 可能有帮助,它是 RequireReloader。

更新: RequireReloader 在这方面对我来说效果很好。它不需要初始化程序来预加载 类.