Rails Single Table Inheritance - Каков наилучший способ явно установить тип? - PullRequest
10 голосов
/ 12 января 2009

Я использую наследование одной таблицы в моем приложении rails и хочу явно установить тип экземпляра.

У меня есть следующее;

class Event < ActiveRecord::Base
class SpecialEvent < Event

, который реализуется посредством наследования одной таблицы.

SpecialEvent.new работает как положено, но я хочу иметь возможность делать что-то вроде

Event.new(:type => 'SpecialEvent')

Так что я могу легко создавать различные подтипы в приложении.

Однако это не работает и, похоже, для :type установлено значение nil, а не значение, которое я установил; Я подозреваю, что это потому, что при вызове Event.new он перезаписывает аргумент :type.

У кого-нибудь есть хороший способ сделать это?

Ответы [ 7 ]

22 голосов
/ 12 января 2009

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

'SpecialEvent'.constantize.new()
14 голосов
/ 01 октября 2009

из "Pragmatic - Agile Web Development с рельсами, 3-е издание", стр. 380

Существует также менее очевидное ограничение (с ИППП). Тип атрибута это также имя встроенного метода Ruby, так что доступ к нему напрямую установить или изменить тип строки может привести к странному Ruby Сообщения. Вместо этого, доступ к нему неявным путем создания объектов соответствующий класс или доступ к нему через индексирование объекта модели интерфейс, используя что-то вроде этого:

person [: type] = 'Менеджер'

человек, эта книга действительно потрясающая

5 голосов
/ 12 января 2009

Нет, я хочу создать экземпляры подтипы, где я хочу программно определить, какие подтип они - Герман

Вы можете использовать фабричный шаблон , хотя недавно я слышал, что люди недовольны чрезмерным использованием этого шаблона. В основном, используйте фабрику для создания фактических типов, которые вы хотите получить

class EventFactory
  def EventFactory.create_event(event_type)
    event_type.constantize.new()
  end
end
2 голосов
/ 04 апреля 2011

Для меня это звучит так, как будто вам понадобится немного моджо в действии event#create:

type = params[:event].delete(:type)

# check that it is an expected value!!!
die unless ['Event', 'SpecialEvent'].include(type)

type.constantize.new(params[:event])
0 голосов
/ 05 марта 2014

Вы можете использовать метод Rails safe_constantize , который обеспечит существование объекта / класса.

Например:

def typeify(string)
  string.classify.safe_constantize
end

new_special_event = typeify('special_event').new
0 голосов
/ 16 апреля 2013

Предварительно, я согласен, что ИППП часто НЕ лучший способ иметь дело с вещами. Полиморфизм, да, но часто лучше использовать полиморфную ассоциацию, чем ИППП.

Тем не менее, у меня была система, в которой была важна ИППП. Это была судебная система, и такие вещи, как судебные дела, были удивительно схожи по своим типам и в целом имели общие черты. Однако гражданское дело и уголовное дело различались по элементам, которыми они управляли. Это произошло на нескольких уровнях в системе, поэтому абстрагировалось мое решение.

https://github.com/arvanasse/sti_factory

Короче говоря, он использует фабричный метод, чтобы использовать общий подход, описанный выше. В результате контроллер может оставаться нейтральным / неосведомленным о конкретном типе класса STI, который вы создаете.

0 голосов
/ 12 января 2009

Судя по всему, Rails не позволяет вам устанавливать тип напрямую. Вот что я делаю ...

klass_name = 'Foo'
...
klass = Class.const_get(klass_name)
klass.new # Foo.new

Я считаю, что .constantize - это ярлык Rails-инфлектора const_get - это метод Ruby для класса и модуля.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...