6

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

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

我是否只是(或者我可以)添加一个包含可能类型的下拉列表,并调用该字段“类型”,以便在提交表单时,rails 将实例化对象的写入类型,因为提供了类型属性?

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

4

2 回答 2

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

用最少的代码对我来说效果很好——我不知道它是否有点骇人听闻,但它可以工作,而且相当干净。我喜欢它只有 10 行代码的事实。

于 2010-02-03T18:51:01.177 回答
0

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

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

缺点当然是更多的文件,无论您链接到“添加新文件”的任何页面都需要添加多个链接,例如“添加新的这种类型的文件”、“添加新的那种类型的文件”等。

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

编辑并添加了基本工作

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

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
于 2010-02-01T15:56:01.760 回答