使用 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 在这方面对我来说效果很好。它不需要初始化程序来预加载 类.
我有 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 在这方面对我来说效果很好。它不需要初始化程序来预加载 类.