I have Rails 4.2 model using STI that is failing on the first attempt to read the record but succeeds on later cases. The record is of type KbtPrimary which inherits from KbTagged which inherits from Keybox. I need to search on KbTagged but the record isn't found on the first read to KbTagged. It is found if the first read is either Keybox or KbtPrimary.
Simplified, the code looks like this:
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};"
And the output is this:
Box:nil;
Box:Automated;
Box:Automated;
If KbtPrimary or Keybox is used first, the output is correct:
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};"
Outputs:
Box:Automated;
Box:Automated;
Box:Automated;
SQL for the first failing read:
"SELECT "keyboxes".* FROM "keyboxes" WHERE "keyboxes"."type" IN ('KbTagged') AND "keyboxes"."company_id" = 2 AND "keyboxes"."name" = 'Automated'"
FURTHER EDIT WITH MORE 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;
The issue is in config/environments/development.rb with the setting:
# Do not eager load code on boot.
config.eager_load = false
Setting this true causes the read to work. However, this isn't really beneficial in a development environment. I am continuing to look for a more optimal solution if you have one.
EDIT: I am currently issuing a require for the STI classes within app/config/initializers to get this done instead of forcing eager_load throughout the application. At this point, I believe that the impact will be that those classes will not be updated dynamically and will require a server restart to be implemented. I did note that there is a gem that might help which is RequireReloader.
UPDATE: RequireReloader is working well for me on this. It does not need the initializer to preload the classes.