10

У меня есть набор подклассов STI, наследующий базовый класс User. Я нахожу, что при определенных условиях внутри определения подкласса запросы в подклассах неправильно используют условие type.ActiveRecord: запрос не использует правильное состояние типа для подкласса STI

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') 

Но при ударе приложения (локальный/пау), то отсутствует условие 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, определенных в подклассе, во время его определения только в среде приложения разработки?

ответ

4

Одно различие между производством и развитием является следующая строка в конфигурации приложения:

# config/environments/development.rb 
config.eager_load = false 

против

# config/environments/production.rb 
config.eager_load = true 

Так что на вашей производственной среде, все ваши clases загружены, когда приложение запускается. Если для параметра eager_load установлено значение false, Rails попытается выполнить автозагрузку класса User при первой загрузке класса Admin.

Учитывая это, я бы предположил, что у вас есть другой класс или модуль с именем User.

FYI: ActiveRecord имеет метод под названием finder_needs_type_condition?.Она должна возвращать верно для класса, который использует STI:

User.finder_needs_type_condition? # should be false 
Admin.finder_needs_type_condition? # should be true 
+0

Спасибо за советы. Я получаю большую нагрузку, но по-прежнему остается загадкой, почему проблема не присутствует в консоли dev, но * присутствует в приложении dev (когда я использую localhost/pow). Метод 'finder_needs_type_condition?' Хорошо знать: пока он возвращает 'true', когда я выхожу из приложения, но все же даю мне' 'SELECT' users'. * FROM 'users'' 'как в вопросе. Кроме того, я нашел частный метод 'type_condition', который при вызове' to_sql' on дает '' '' users''type' IN ('Admin') '' '. Так что что-то явно сломалось. –

+0

Связанный, я ** ** не смог воспроизвести это поведение на другом подклассе STI совершенно другого базового класса, так что это, похоже, имеет отношение к классу 'User'. Прогресс ... –

+0

Еще одно обновление: я прокомментировал * все * в моем базовом классе 'User', кроме самого объявления класса, и проблема сохраняется. Поэтому я не вижу, что может быть особенным в этом классе сейчас, или как все, что вызывает эту проблему, исчезает после завершения определения класса. –

1

В настоящее время, любой User будет пустой :type столбец. Может ли это быть проблемой?

Вы пытались сделать User супер класс? Например.

class User < ActiveRecord::Base 
end 

class Admin < User; end 
class NormalUser < User; end 
+0

Исправьте меня, если я что-то не понимаю, я никогда не использовал 'abstract_class' в Ruby/Rails. Читая документы, я вижу, что 'abstract_class' должен быть установлен в' true', если я делаю * not * хочу, чтобы подклассы использовали одно и то же имя таблицы. Но я знаю, поэтому я не уверен, что это правильно для моего случая использования. Когда я пытаюсь это сделать, я получаю то, что вы можете ожидать: 'ActiveRecord :: StatementInvalid: Mysql2 :: Ошибка: Таблица 'threeplay_development.admins' не существует'. Что вы имели в виду под любым «Пользователем», будет иметь пустой столбец типа? Таблица 'users' заполняется правильно, мне просто нужно загрузить эти данные, когда приложение запустится. –

+0

Уппс, вы правы с 'abstract_class': Это был вздор. Тем не менее, проблема ** пуста ** ': type'. Когда вы выполняете 'User.create ({attributes ....})' без указания ': type', он получает значение« nil ». То же самое с 'Admin.create (...)' устанавливает автоматически 'type = 'Admin''. – andiba

+0

Да, спасибо за ответ. Данные уже существуют и содержат заполненный столбец 'type' (текущий 13k total' User's, из них 23 'Admin's). Здесь я просто читаю из таблицы, используя 'Admin.all' (или' self.all' в определении класса 'Admin'), и он не генерирует соответствующее предложение WHERE при указанном выше конкретном условии. –

Смежные вопросы