Rails单表继承 - 显式设置类型的最佳方法是什么?

时间:2009-01-12 15:03:40

标签: ruby-on-rails

我在rails应用程序中使用single table inheritance,并希望显式设置实例的类型。

我有以下内容;

class Event < ActiveRecord::Base
class SpecialEvent < Event

通过单表继承实现。

SpecialEvent.new按预期工作,但我希望能够执行

之类的操作
Event.new(:type => 'SpecialEvent')

因此,我可以在应用程序中轻松创建不同的子类型。

但是这不起作用,似乎将:type设置为nil,而不是我设置的值;我怀疑这是因为通过调用Event.new它会覆盖:type参数。

有没有人有这样做的好方法?

7 个答案:

答案 0 :(得分:22)

如果您尝试动态实例化子类型,并且您将类型作为字符串,则可以执行以下操作:

'SpecialEvent'.constantize.new()

答案 1 :(得分:14)

来自“务实 - 使用rails第3版的敏捷Web开发”,第380页

  

还有一个不太明显的约束(使用STI)。属性类型   也是内置Ruby方法的名称,因此直接访问它   设置或更改行的类型可能会导致奇怪的Ruby   消息。相反,通过创建对象隐式访问它   适当的类,或通过模型对象的索引访问它   界面,使用如下内容:

     

person [:type] ='经理'

男人,这本书真的很摇滚

答案 2 :(得分:5)

  

不,我想创建的实例   子类型,我想要的地方   以编程方式确定哪个   他们是sub_type    - HermanD

你可以使用factory pattern,虽然我最近听说人们对过度使用这种模式感到不满。基本上,使用工厂来创建您想要的实际类型

class EventFactory
  def EventFactory.create_event(event_type)
    event_type.constantize.new()
  end
end

答案 3 :(得分:2)

对我来说,听起来你需要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])

答案 4 :(得分:0)

显然,Rails不允许您直接设置Type。这就是我做的......

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

我相信.constantize是一个Rails偏转器快捷方式。 const_get是Class和Module上的Ruby方法。

答案 5 :(得分:0)

预先我会同意STI通常不是处理事情的最佳方式。多态性,是的,但使用多态关联通常比STI更好。

那就是说,我有一个STI很重要的系统。这是一个司法系统,诸如法庭案件之类的事情在其类型上非常相似,并且通常共享其所有基本属性。但是,民事案件和刑事案件在他们管理的要素上存在差异。这发生在系统的几个层面,因此抽象了我的解决方案。

https://github.com/arvanasse/sti_factory

长话短说,它使用工厂方法来利用上述常用方法。因此,控制器可以保持中立/不知道您正在创建的特定类型的STI类。

答案 6 :(得分:0)

您可以使用Rails safe_constantize方法,这将确保对象/类实际存在。

例如:

def typeify(string)
  string.classify.safe_constantize
end

new_special_event = typeify('special_event').new