У меня есть пользователь, а у них есть домашние животные. Все виды домашних животных. Рептилии, рыбы, птицы и млекопитающие. Модель млекопитающих имеет два подкласса, унаследованных посредством наследования одной таблицы (STI): кошки и собаки. У моего пользователя есть способ получить своего последнего питомца.
В контроллере статических страниц у меня есть метод для посещения последнего питомца пользователя:
def go_to_pet
redirect_to current_user.last_pet || root_path
end
Теперь проблема, с которой я сталкиваюсь, заключается в том, что когда кошка или собака возвращаются в качестве последнего домашнего животного пользователя, приложение ищет контроллер кошек или собак, но у меня есть и нужен только контроллер млекопитающих. Контроллер млекопитающих довольно хорошо обрабатывает как кошек, так и собак, когда он фактически вызывается.
Мой вопрос таков: как я могу получить экземпляр класса Mammal? Я пробовал Mammal.find(cat.id), но он автоматически возвращает кошку, потому что в этом весь смысл STI.
Единственный уродливый обходной путь, который я могу придумать, - это проверить класс в контроллере статических страниц (в блоке кода выше), а затем использовать redirect_to для использования контроллера млекопитающих, но я бы предпочел избежать этого.
Я попытался явно загрузить базовый класс через Mammal.find(cat.id), но он автоматически вернул экземпляр унаследованного класса Cat на основе столбца типа. Я надеялся получить экземпляр класса Mammal.
ооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооо) Почему-то я предположил, что это работает только для изменения базового класса на производный класс. Большое спасибо!
если вам не нужен экземпляр Mammal
в представлении, вы можете redirect_to mammal_url(current_user.last_pet.id)
и передать кота как @pet = current_user.last_pet
, который будет экземпляром Cat
К сожалению, это не сработает, потому что это может также вернуть рептилию, рыбу или птицу, у которых нет url-адреса млекопитающее_.
Обновление: после того, как я написал этот ответ, был опубликован уже принятый ответ, который назначает правильный контроллер в route.rb. Это решает мою проблему еще лучше.
Алексей написал правильный ответ в комментарии к вопросу. Это:
becomes(Mammal)
Документация по api.rubyonrails.org
Я вызываю это в пользовательской модели при получении последнего питомца следующим образом:
if @pet.instance_of?(Cat) || @pet.instance_of?(Dog)
@pet = @pet.becomes(Mammal)
end
Так что теперь я могу уверенно перенаправлять с помощью redirect_to current_user.last_pet || root_path
. Еще раз спасибо Алексу.
Если вы добавите больше Mammal
, это может стать неуклюжим. Я не уверен, является ли Mammal
абстрактным или нет, но что-то вроде @pet.becomes(@pet.class.base_class)
может сработать.
Я думаю, ты пытаешься выстрелить себе в ногу. Если у вас есть класс Dog и Cat, а не просто класс Mammal, то они, вероятно, заслуживают своих собственных контроллеров. И если они ведут себя одинаково, просто сделайте их тривиальными подклассами родителя с общим поведением.
Но если вы действительно хотите сделать то, что описываете, я бы, наверное, сделал что-то вроде:
def go_to_pet
last_pet = current_user.last_pet
if last_pet.class.superclass.abstract_class?
redirect_to url_for(controller: last_pet.class.base_class.name.tableize, id; last_pet.id)
else
redirect_to current_user.last_pet || root_path
end
end
Но в основном я бы, вероятно, просто отключил его на маршрутах.
resources :dogs, controller: 'mammals'
Назначение контроллера в route.rb — это именно то, что мне нужно. Спасибо!
current_user.last_pet.becomes(Mammal)
api.rubyonrails.org/classes/ActiveRecord/…