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