Рельсы - наследование одной таблицы - ошибочный подход к литью? - PullRequest
1 голос
/ 27 июля 2011

Итак, я в последнее время изучал наследование отдельных таблиц и нашел этот общий вопрос / ответ:

вопрос: как изменить класс объекта obj с Альфы на Бета, при условии Бета <Альфа, в ИППП? </p>

ответ: ruby ​​- это типизированный язык, так что вы не используете кастинг. Но все, что вам нужно сделать, это установить переменную "type" в "Beta" и сохранить объект, и при следующей загрузке объекта Alpha он будет иметь тип Beta:

obj = Alpha.new
obj.save #now obj is of type Alpha

obj.type = "Beta"
obj.save #now obj is of type Beta

Однако этот подход, похоже, не работает для меня. Хотя obj правильно сохраняет данные, похоже, он вообще не функционирует как бета-объект. Он сохраняет без запуска бета-проверки, и когда я проверил obj.respond_to?(:beta_method) #beta_method being a method in the beta class, он вернул false. Этот подход не работает? Есть ли правильный подход? Или я просто что-то делаю не так?

EDIT

Я обнаружил, что когда я выполнял Alpha.last.respond_to (: beta_method), он возвращал false, а Beta.last.respond_to (: beta_method) возвращал true (однако и Alpha.last, и Beta.last возвращали один и тот же объект). Интересное развитие? Тем не менее, если бы кто-то мог объяснить это подробно (относительно того, как ruby ​​обрабатывает наследование), это было бы здорово.

Ответы [ 2 ]

4 голосов
/ 27 июля 2011

В зависимости от того, что вы пытаетесь выполнить, вы можете либо использовать becomes, либо изменить тип объекта, как вы сделали (или напрямую через update_attribute), и перезагрузить его из база данных (или может и то и другое).

becomes создаст экземпляр и возвратит новый объект класса, переданный в качестве единственного параметра, используя те же атрибуты, что и предыдущий объект. Это позволит вам вызывать методы нового объекта. Например:

a = Alpha.last

# if you want to save the new type in the database:
a.type = 'Beta' 
a.save

b = a.becomes(Beta)
b.respond_to?(:beta_method)
=> true

Я обнаружил, что порядок, в котором вы вызываете методы, важен. Если вы попытаетесь сначала использовать becomes, а затем изменить тип и сохранить, это не изменит тип в базе данных.

1 голос
/ 27 июля 2011

Как вы сказали, Ruby не разрешает приведение типов. Скорее, здесь происходит то, что ActiveRecord создает экземпляр другого класса в зависимости от значения поля type. Поэтому, когда вы меняете его на «бета», вы на самом деле ничего не делаете с точки зрения Руби.

Но когда ActiveRecord просматривает базу данных для извлечения записи, он видит новое значение type и создает экземпляр Beta, а не Alpha. Этот процесс имеет меньшее отношение к Ruby, чем к ActiveRecord, в частности.

Иногда есть более элегантные подходы в зависимости от вашей ситуации. Если вам нужно «преобразовать» модель из одного типа в другой (например, Employee становится Manager, у которого есть дополнительные методы), это разумный способ. В других случаях ваша цель может быть лучше достигнута с помощью миксинов или другого инструмента.

Вы также можете создать временный экземпляр Beta из атрибутов Alpha, если вам нужно, например:

# obj is an instance of Alpha
obj = Beta.new(obj.attributes)

Но это также странная вещь, которую нужно делать в большинстве случаев.

...