问题
I have a set of STI subclasses inheriting from a User
base class. I am finding that under certain conditions inside a subclass' definition, queries on the subclasses do not correctly use the type
condition.
class User < ActiveRecord::Base
# ...
end
class Admin < User
Rails.logger.info "#{name}: #{all.to_sql}"
# ...
end
When loading the Rails console in development, it does what I would expect:
Admin: SELECT `users`.* FROM `users` WHERE `users`.`type` IN ('Admin')
But when hitting the app (localhost / pow), it is missing the type
condition and I get this:
Admin: SELECT `users`.* FROM `users`
But not from the app when when deployed to a staging server:
Admin: SELECT `users`.* FROM `users` WHERE `users`.`type` IN ('Admin')
This, of course, causes any queries executed here in the dev app (but not from the console) to be incorrect. Specifically, I am trying to preload a (small) cache of existing db values in order to create a few helpful methods based on those data. Without the type scope, the cache is obviously incorrect!
From the same location (Admin
), we get the following confusing contradiction:
[11] pry(Admin)> Admin.finder_needs_type_condition?
=> true
[12] pry(Admin)> Admin.send(:type_condition).to_sql
=> "`users`.`type` IN ('Admin')"
[13] pry(Admin)> Admin.all.to_sql
=> "SELECT `users`.* FROM `users`"
Further, I defined a throwaway subclass Q < User
inside the user.rb
file. I logged Q.all.to_sql
from its definition, from the definition of Admin
, and from a view. In that order, we get:
From Q: Q: SELECT `users`.* FROM `users` WHERE `users`.`type` IN ('Q')
From Admin: Q: SELECT `users`.* FROM `users`
From View: Q: SELECT `users`.* FROM `users` WHERE `users`.`type` IN ('Q')
What could cause, in the first line of the Admin
subclass definition in admin.rb, any subclass of User
to fail to use its type_condition
?
This is causing development tests to fail, and so is of some consequence to my app. What on earth could be causing this difference in behavior? Can anyone think of a more general way around the problem of not having the STI conditions defined on a subclass during its definition only in the development app environment?
回答1:
One difference between production and development is the following line inside of the application configuration:
# config/environments/development.rb
config.eager_load = false
vs.
# config/environments/production.rb
config.eager_load = true
So on your production environment, all your clases are loaded when the app is started.
When eager_load
is set to false, Rails will try to autoload your User
class when you first load the Admin
class.
Given that, I'd assume that you have another class or module named User
.
FYI: ActiveRecord has a method called finder_needs_type_condition?
. It should return true for a class that uses STI:
User.finder_needs_type_condition? # should be false
Admin.finder_needs_type_condition? # should be true
回答2:
Currently, any User
will have an empty :type
column. Could this is be a problem?
Have you tried to make User
a super class? E.g.
class User < ActiveRecord::Base
end
class Admin < User; end
class NormalUser < User; end
来源:https://stackoverflow.com/questions/36992467/activerecord-query-not-using-correct-type-condition-for-sti-subclass