ActiveRecord: запрос не использует правильное состояние типа для подкласса STI
У меня есть набор подклассов STI, наследующих от базового класса User
. Я нахожу, что при определенных условиях внутри определения подкласса запросы в подклассах неправильно используют условие type
.
class User < ActiveRecord::Base
# ...
end
class Admin < User
Rails.logger.info "#{name}: #{all.to_sql}"
# ...
end
При загрузке консоли Rails в разработке она делает то, что я ожидаю:
Admin: SELECT `users`.* FROM `users` WHERE `users`.`type` IN ('Admin')
Но при попадании в приложение (localhost/pow) отсутствует условие type
, и я получаю следующее:
Admin: SELECT `users`.* FROM `users`
Но не из приложения, когда оно развертывается на промежуточном сервере:
Admin: SELECT `users`.* FROM `users` WHERE `users`.`type` IN ('Admin')
Это, конечно же, вызывает неправильные запросы, которые выполняются в приложении dev (но не с консоли). В частности, я пытаюсь предварительно загрузить (небольшой) кэш существующих значений db, чтобы создать несколько полезных методов на основе этих данных. Без области видимости кеш, очевидно, неверен!
Из того же места (Admin
) получаем следующее противоречивое противоречие:
[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`"
Кроме того, я определил выделенный подкласс Q < User
внутри файла user.rb
. Я записал Q.all.to_sql
из своего определения из определения Admin
и из представления. В этом порядке получаем:
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')
Что может привести к тому, что в первой строке определения подкласса Admin
в admin.rb любой подкласс User
не сможет использовать его type_condition
?
Это приводит к сбою тестов разработки и, как следствие, к моему приложению. Что может быть причиной этой разницы в поведении? Может ли кто-нибудь подумать о более общем способе решения проблемы отсутствия условий STI, определенных в подклассе, во время его определения только в среде разработки приложений?
Ответы
Ответ 1
Одна разница между производством и разработкой - это следующая строка внутри конфигурации приложения:
# config/environments/development.rb
config.eager_load = false
против.
# config/environments/production.rb
config.eager_load = true
Итак, в вашей рабочей среде все ваши кланы загружаются при запуске приложения.
Если для параметра eager_load
установлено значение false, Rails попытается автоматически загрузить ваш класс User
при первой загрузке класса Admin
.
Учитывая это, я бы предположил, что у вас есть другой класс или модуль с именем User
.
FYI: ActiveRecord имеет метод под названием finder_needs_type_condition?
. Он должен возвращать true для класса, который использует STI:
User.finder_needs_type_condition? # should be false
Admin.finder_needs_type_condition? # should be true
Ответ 2
В настоящее время любой User
будет иметь пустой столбец :type
. Может ли это быть проблемой?
Вы пытались сделать User
суперкласс? Например.
class User < ActiveRecord::Base
end
class Admin < User; end
class NormalUser < User; end