ActiveRecord: query not using correct type condition for STI subclass

我的梦境 提交于 2021-01-27 00:33:07

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!