简体   繁体   English

Rails嵌套属性表单用于多态/单表继承关联

[英]Rails nested attributes form for polymorphic/single table inheritance associations

I am working on a form (using SimpleForm) that allows you to edit embedded associations. 我正在使用一个表单(使用SimpleForm),允许您编辑嵌入的关联。 The problem that I'm running into is that the nested models are subclasses so they are different types with potentially different fields. 我遇到的问题是嵌套模型是子类,因此它们是具有可能不同字段的不同类型。 I'm creating hidden forms for each type of model, and using JavaScript to display the form for the selected type. 我正在为每种类型的模型创建隐藏表单,并使用JavaScript显示所选类型的表单。

FYI, I'm using the following gems: 仅供参考,我使用以下宝石:

  • Rails 3.2 Rails 3.2
  • Mongoid Mongoid
  • SimpleForm 简单的形式

Here's a simplified example of what I have so far: 这是我到目前为止的简化示例:

class Garage
  include Mongoid::Document
  embeds_one :vehicle
  accepts_nested_attributes_for :vehicle
end

class Vehicle
  include Mongoid::Document
  embedded_in :garage
  attr_accessible :_type
end

class Car < Vehicle
  field :car_field
  attr_accessible :car_field
end

class Truck < Vehicle
  field :truck_field
  attr_accessible :truck_field
end

In the console: 在控制台中:

> garage = Garage.new
> garage.vehicle = Car.new(car_field: 'something')
> garage.save!

In the form: 形式如下:

= simple_form_for @garage do |f|
  = f.input :vehicle do |vehicle_form|
     = vehicle_form.input :_type, collection: ['Car', 'Truck']

  %span.hide{data:{fields-for:'Car'}}
    = vehicle_form.input :car_field

  %span.hide{data:{fields-for:'Truck'}}
    = vehicle_form.input :truck_field

:coffeescript
  $('#garage_vehicle_attributes__type').change ->
    type = $(@).find('option:selected').val()
    $('[data-fields-for="' + type + '"]').show()

The problem that will occur in this example is that it won't be able to render the truck_field because Car does not have a truck_field method. 此示例中将出现的问题是它无法渲染truck_field因为Car没有truck_field方法。 I'm not sure how to solve this problem besides throwing out any form helpers and managing the html and field values manually. 除了抛弃任何表单助手并手动管理html和字段值之外,我不确定如何解决这个问题。 Even after much Googling, I haven't been able to find any examples of this type of form. 即使经过谷歌搜索,我也无法找到这种形式的任何例子。

How can this problem be solved in a standard, "Rails way" using existing form helpers? 如何使用现有的表单助手以标准的“Rails方式”解决这个问题?

I think I had a similar problem, however instead of a has_one relationship, I have has_many . 我认为我遇到了类似的问题,但是我有一个has_many而不是has_one关系。

Basically I used cocoon gem to dynamically add fields for each decorated class (such as Car or Truck ) and then I accept_nested_attributes_for :vehicle . 基本上我使用cocoon gem为每个装饰类(例如CarTruck )动态添加字段,然后我使用accept_nested_attributes_for :vehicle The form is built dynamically and on submit, the parameters go inside vehicle_attributes . 表单是动态构建的,在提交时,参数在vehicle_attributes

The code looks something like (updated for has_one association): 代码看起来像(为has_one关联更新):

# _form.html.haml

= simple_form_for @garage, :html => { :multipart => true } do |f|

  = f.simple_fields_for :vehicles do |vehicle|
    = render 'vehicle_fields', :f => item
    = link_to_add_association 'Add a Car', f, :vehicles, :wrap_object => Proc.new { |vehicle| vehicle = Car.new }
    = link_to_add_association 'Add a Truck', f, :vehicles, :wrap_object => Proc.new { |vehicle| vehicle = Truck.new }

= f.button :submit, :disable_with => 'Please wait ...', :class => "btn btn-primary", :value => 'Save' 

Then inside _vehicle_fields partial you check what object it is ( Car or Truck ) and you render the correct fields. 然后在_vehicle_fields部分内部检查它是什么对象( CarTruck )并渲染正确的字段。

I think this works quite good, and was exactly what I needed. 我认为这很有效,而且正是我所需要的。 Hope it helps. 希望能帮助到你。

I wrote a longer explanation at: http://www.powpark.com/blog/programming/2014/05/07/rails_nested_forms_for_single_table_inheritance_associations 我在以下网址写了一篇更长的解释: http//www.powpark.com/blog/programming/2014/05/07/rails_nested_forms_for_single_table_inheritance_associations

This is one of those situations where directly mapping a form to a model is not ideal. 这是直接将表单映射到模型的情况之一。 I think a user-filled form map and a persistence model instance are two very distinct concepts. 我认为用户填充的表单映射和持久性模型实例是两个截然不同的概念。

You might try subclassing Vehicle into a class that is used to accept form data. 您可以尝试将Vehicle子类化为用于接受表单数据的类。 Then mix in all the extra code you need to handle what is specific to the form. 然后混合使用所需的所有额外代码来处理表单特有的内容。 This way, you keep your Vehicle model clean. 这样,您可以保持Vehicle模型清洁。 You can also override methods in VehicleFormModel to work like a factory, to build the correct instance when the object is being created. 您还可以覆盖VehicleFormModel方法以像工厂一样工作,以在创建对象时构建正确的实例。 In your controller, instantiate a VehicleFormModel instead of a Vehicle. 在您的控制器中,实例化VehicleFormModel而不是Vehicle。

class VehicleFormModel < Vehicle
  include Car::FormModel
  include Truck::FormModel

  def self.build
    # Use a form field to handle specifics for each type,
    # delegating to the mixed in FormModel as needed
  end

end

class Car < Vehicle
  module FormModel
    def self.included(base)
      base.class_eval do
        field :car_field
        attr_accessible :car_field
      end
    end
  end
end

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM