Take the 2-minute tour ×

I am working on a form (using SimpleForm) that allows you to edit embedded associations. 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.

FYI, I'm using the following gems:

  • Rails 3.2
  • 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

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

class Car < Vehicle
  field :car_field
  attr_accessible :car_field

class Truck < Vehicle
  field :truck_field
  attr_accessible :truck_field

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']

    = vehicle_form.input :car_field

    = vehicle_form.input :truck_field

  $('#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. I'm not sure how to solve this problem besides throwing out any form helpers and managing the html and field values manually. 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?

share|improve this question
maybe this can help: stackoverflow.com/questions/3327236/… (but not sure) –  jethroo Jul 1 '13 at 20:52
@jethroo thanks, but unfortunately the answer covers everything I already have in my code sample. They leave off the last step of working with different fields for different models. –  Andrew Jul 1 '13 at 21:29
If the base document haven't got any common fields, I would think on the lines of creating two sets of fields, one for truck(with a new blank instance) and one for car, setting _destroy on vehicle type switch and creating a new truck document. If that doesn't work for you or seems too inelegant, other option is to move all fields to base document, because if you convert car to a truck, I believe mongoid will not unset car_field and your document in db will have more fields than it needs. Right way to switch document type is to assign new document and not edit existing in place IMHO. –  rubish Jul 4 '13 at 0:19
@rubish Good tip, I discovered that as well. I have an embeds_many association too, so the solution for that is a little different. –  Andrew Jul 4 '13 at 4:18
I think embeds_many is relatively easy to handle than embeds one, as you can destroy old documents and create new ones in a single call using existing mechanisms of nested attributes. However, with embeds_one, you will need to create new document and override existing one and also make sure that if there is any cleanup to be done on destroying the document(like deleting s3 files), its taken care of properly. –  rubish Jul 4 '13 at 6:06
show 4 more comments

1 Answer

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. 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. You can also override methods in VehicleFormModel to work like a factory, to build the correct instance when the object is being created. In your controller, instantiate a VehicleFormModel instead of a 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


class Car < Vehicle
  module FormModel
    def self.included(base)
      base.class_eval do
        field :car_field
        attr_accessible :car_field
share|improve this answer
I see there's a Railscast that might cover this: railscasts.com/episodes/416-form-objects –  aceofspades Jul 7 '13 at 20:46
Interesting idea. I would like to see more of the HTML/JavaScript implementation for this though. –  Andrew Jul 9 '13 at 21:06
I watched the RailsCast again, it's pretty comprehensive. –  aceofspades Jul 10 '13 at 0:49
I've already seen the screencast. I was referring to the specifics of this type of form that creates different fields based on a previous field you select. –  Andrew Jul 10 '13 at 16:56
Dynamic forms is at railscasts.com/episodes/403-dynamic-forms –  aceofspades Jul 10 '13 at 22:54
add comment

Your Answer


