代码之家  ›  专栏  ›  技术社区  ›  DanSingerman

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

  •  10
  • DanSingerman  · 技术社区  · 17 年前

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

    class Event < ActiveRecord::Base
    class SpecialEvent < Event
    

    它是通过单表继承实现的。

    SpecialEvent.new 工作如预期,但我想能够做的事情,如

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

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

    然而,这不起作用,似乎设置 :type 到 nil ,而不是我设置的值;我怀疑这是因为 Event.new 它正在覆盖 :类型 论点

    有人有好的方法吗?

    7 回复  |  直到 9 年前
        1
  •  22
  •   Codebeef    17 年前

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

    'SpecialEvent'.constantize.new()
    
        2
  •  14
  •   buræquete Naveen Kocherla    9 年前

    摘自“实用-rails第三版敏捷Web开发”,第380页

    还有一个不太明显的约束(对于STI)。属性类型 也是内置Ruby方法的名称,因此可以直接访问它 设置或更改行的类型可能会导致奇怪的错误 适当的类,或通过模型对象索引访问它

    人员[:类型]=“经理”

        3
  •  5
  •   Bill    17 年前

    否,我想创建的实例 子类型,在我想要的地方 以编程方式确定 它们是亚型的 赫尔曼德

    你可以用一个 factory pattern ,尽管我最近听说人们对这种模式的过度使用表示不满。基本上,使用工厂创建您想要获得的实际类型

    class EventFactory
      def EventFactory.create_event(event_type)
        event_type.constantize.new()
      end
    end
    
        4
  •  2
  •   Dave Newton    14 年前

    对我来说,听起来你需要一些魔咒 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])
    
        5
  •  0
  •   kt103099    17 年前

    显然,Rails不允许您直接设置类型。我就是这么做的。。。

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

    我相信,constantize是一条捷径。const_get是类和模块上的Ruby方法。

        6
  •  0
  •   AndyV    13 年前

    也就是说,我有一个STI很重要的系统。这是一个司法系统,像法庭案件这样的事情在不同类型的案件中有着惊人的相似性,并且总体上具有所有的基本特征。然而,民事案件和刑事案件在处理的要素上有所不同。这发生在系统的多个级别,因此抽象了我的解决方案。

    https://github.com/arvanasse/sti_factory

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

        7
  •  0
  •   Adam    12 年前

    你可以用铁轨 safe_constantize

    def typeify(string)
      string.classify.safe_constantize
    end
    
    new_special_event = typeify('special_event').new