Ответ 1
Если вы пытаетесь динамически создавать подтип, и у вас есть тип в виде строки, вы можете сделать это:
'SpecialEvent'.constantize.new()
Я использую однонамерное наследование в моем приложении rails и хочу явно указать тип экземпляра.
У меня есть следующее:
class Event < ActiveRecord::Base
class SpecialEvent < Event
который реализуется посредством наследования одной таблицы.
SpecialEvent.new
работает так, как ожидалось, но я хочу иметь возможность делать такие вещи, как
Event.new(:type => 'SpecialEvent')
Таким образом, я могу легко создавать различные типы sub_types в приложении.
Однако это не работает и, кажется, устанавливает :type
в nil
, а не значение, которое я ему задал; Я подозреваю, что это вызвано тем, что при вызове Event.new
он перезаписывает аргумент :type
.
Кто-нибудь получил хороший способ сделать это?
Если вы пытаетесь динамически создавать подтип, и у вас есть тип в виде строки, вы можете сделать это:
'SpecialEvent'.constantize.new()
от "Pragmatic - Agile Web Development с рельсами 3-го издания", стр. 380
Theres также менее очевидное ограничение (с STI). Тип атрибута также является именем встроенного Ruby-метода, поэтому доступ к нему напрямую для установки или изменения типа строки может привести к появлению странного Ruby Сообщения. Вместо этого обращайтесь к нему неявно, создав объекты соответствующий класс или доступ к нему через индексирование объектов модели интерфейс, используя что-то вроде этого:
person [: type] = 'Manager'
человек, эта книга действительно качает
Нет, я хочу создать экземпляры подтипы, где я хочу программно определить, какие sub_type они - HermanD
Вы можете использовать factory образец, хотя я недавно слышал, что люди недовольны чрезмерным использованием этого шаблон. В принципе, используйте factory для создания фактических типов, которые вы хотите получить
class EventFactory
def EventFactory.create_event(event_type)
event_type.constantize.new()
end
end
Мне кажется, что вам понадобится несколько mojo в действии 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])
По-видимому, Rails не позволяет вам устанавливать Type напрямую. Вот что я делаю...
klass_name = 'Foo'
...
klass = Class.const_get(klass_name)
klass.new # Foo.new
Я считаю, что .constantize - это ярлык фальцевого Rails. const_get - это метод Ruby для класса и модуля.
Наверху Я соглашусь, что STI часто не лучший способ справиться с вещами. Полиморфизм, да, но часто лучше использовать полиморфную ассоциацию, чем STI.
Тем не менее, у меня была система, в которой важна ИППП. Это была судебная система, и такие вещи, как судебные дела, были удивительно похожи по их типам и, как правило, разделяли все их основные атрибуты. Однако гражданское дело и уголовное дело отличались элементами, которыми они управляли. Это произошло на нескольких уровнях в системе, поэтому я отвлек свое решение.
https://github.com/arvanasse/sti_factory
Короче говоря, он использует метод factory для использования общего подхода, описанного выше. В результате контроллер может оставаться нейтральным/не осведомленным о конкретном типе класса STI, который вы создаете.
Вы можете использовать метод Rails safe_constantize, который гарантирует, что объект/класс действительно существует.
Например:
def typeify(string)
string.classify.safe_constantize
end
new_special_event = typeify('special_event').new