Rails nested attribute form for polymorphic / single table inheritance associations

I am working on a form (using SimpleForm) that allows editing inline associations. The problem I am facing is that nested models are subclasses, so they are different types with potentially different fields. I create hidden forms for each type of model and using JavaScript to display the forms for the selected type.

FYI, I use the following stones:

  • Rails 3.2
  • Mongoid
  • Simpleform

Here is a simplified example of what I still have:

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 shape of:

 = 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 arise in this example is that it will not be able to display truck_field because Car does not have a truck_field method. I am not sure how to solve this problem, besides pulling out any form helpers and managing the html and field values ​​manually. Even after a lot of Googling, I could not find examples of this type of form.

How can this problem be solved in standard "Rails" mode using existing form helpers?

+4
source share
2 answers

I think I had a similar problem, however, instead of the has_one relationship, I have has_many .

I basically used cocoon gem to dynamically add fields for each decorated class (like Car or Truck ), and then I accept_nested_attributes_for :vehicle . The form is built dynamically and at the input the parameters enter the vehicle_attributes .

The code looks something like this (updated for has_one association):

 # _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 which object it is ( Car or Truck ), and you display the correct fields.

I think this works well, and that is exactly what I need. Hope this helps.

I wrote a longer explanation at: http://www.powpark.com/blog/programming/2014/05/07/rails_nested_forms_for_single_table_inheritance_associations

+2
source

This is one of those situations where the direct mapping of a form into a model is not ideal. I think the user-filled map form and instance of the persistence model are two very clear concepts.

You can try to subclass Vehicle in a class that is used to receive form data. Then mix all the extra code needed to process what is characteristic of the form. This way you keep your Vehicle model clean. You can also override methods in VehicleFormModel to VehicleFormModel as a factory to create the correct instance when creating the object. In the controller, create an instance of VehicleFormModel instead of the 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 
+1
source

Source: https://habr.com/ru/post/1489150/


All Articles