使用ONE表单的Rails STI

时间:2010-02-01 06:19:03

标签: ruby-on-rails polymorphism single-table-inheritance

我有一个表单,允许我将不同格式的文件添加到流中。因此,流由许多文件组成,这些文件是XML文件,但基本上有不同的模式。我有一个表单,允许用户添加他们想要的任何文件,我正在使用STI(当数据已经在表中时效果很好),我的麻烦是将数据添加到表中。

表单有1个输入字段,只有一个file_field,允许用户选择要上传的文件。由于我只有一个表单,我无法实例化正确的对象,我必须以编程方式进行...而且我不知道该怎么做。

我只是(或者我可以)添加可能类型的下拉列表,并调用该字段'type',以便在提交表单时,rails将实例化对象的写入类型,因为提供了type属性?< / p>

最佳做法是什么..我正在运行rails 2.3.4。

2 个答案:

答案 0 :(得分:3)

我在http://coderrr.wordpress.com/2008/04/22/building-the-right-class-with-sti-in-rails/#comment-1826

找到了解决方案
class GenericClass < ActiveRecord::Base
  class << self
    def new_with_cast(*a, &b)
      if (h = a.first).is_a? Hash and (type = h[:type] || h['type']) and (klass = type.constantize) != self
        raise "wtF hax!!"  unless klass < self  # klass should be a descendant of us
        return klass.new(*a, &b)
      end

      new_without_cast(*a, &b)
    end
    alias_method_chain :new, :cast
  end
end

对于我来说,使用最少的代码对我来说非常有用 - 我不知道它的hackish与否,但是它有效,并且相当干净。我喜欢它只有10行代码的事实。

答案 1 :(得分:0)

我不知道你有多少种类型,但我过去只使用过不同类型的独立控制器和视图。这样您就不会创建基类的新对象并尝试设置类型,您只需使用从基类继承的模型。资源的每个新/编辑页面都可以在form_for块中呈现共享部分。部分将包含您的file_field。

这样当提交表单时,它将转到正确的控制器,调用正确的resource.new,一切正常。

缺点当然是更多的文件和你链接到“添加新文件”的任何页面,你需要添加多个链接,如“添加新的这种类型的文件”,“添加新的那种类型的文件”等< / p>

至于在表单中设置类型我不确定它是否有效,我对此表示怀疑,但试试看(让我们知道)。您可以将该类型下拉为select_tag,并在更改时使用Javascript更改表单上的操作位置。

编辑并添加了基本工作

不是我喜欢这个解决方案&amp;我怀疑它绝不是最好的,但是如果你真的不想要单独的控制器并且你需要让它工作,你可以做这样的事情:

class XmlFile < ActiveRecord::Base
end

class XmlFileTypeA < XmlFile 
end

class XmlFileTypeB < XmlFile 
end

def create
    # Leaving this case statement in the controller for simplicity but you probably want to move this to the model
    case params[:chosen_xml_type]
      when "file_type_a"
        @item = XmlFileTypeA.new(params)
      when "file_type_b"
        @item = XmlFileTypeB.new(params)
      else
        raise "Unknown file type!"
      etc
    end
end