Reputation: 43113
Update: After thinking about this some more I think this question includes both polymorphism and STI.
Let's say I have the following:
class Vehicle < ActiveRecord::Base
belongs_to :dealership
...
end
class Car < Vehicle
...
end
class Truck < Vehicle
...
end
The Car and Truck models have the same attributes but different logic in the model, so they all just use the Vehicles table.
I'd like to make a generic form that allows someone to create a new vehicle record, and to select whether it is a "Car" or "Truck". On the backend this form should then create a "Car" or "Truck" record, not a generic "Vehicle" record.
Question: How do you present this option in a Rails form? Specifically, are there methods for listing the child types of an abstract base model, and/or is there a simple way to present these as (for instance) a Select element in a form?
The reason I am looking to create a form that can make a car or a truck opposed to just having two different forms for cars and trucks, is eventually I'd also like these models to be nested in a parent, "Dealership." I'd like to be able to not only create new vehicles and select "car" or "truck" as an option, but to be able to have nested forms where a user could load a "Dealership" and view/edit all the cars and trucks that belong to that dealership in a single form. I know how to set that up using accepts_nested_attributes_for
on a simple association like Vehicle belongs_to :dealership
, but I'm not sure how to set it up for child models that inherit from Vehicle.
Upvotes: 1
Views: 1299
Reputation: 1417
I've had the same problem. Basically you are trying to build a form that accepts has_many
association of a base class, but you want to create individual forms (add nested fields) for any of the Decorated / Concrete classes dynamically.
I solved this using the cocoon
gem, which provided methods that dynamically add the correct fields to the form. The _form
partial looks something like:
# _form.html.haml
= simple_form_for @dealership, :html => { :multipart => true } do |f|
= f.simple_fields_for :vehicles do |vehicle|
= render 'vehicle_fields', :f => vehicle
= 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'
And then the _vehicle_fields
# _vehicle_fields.html.haml
- if f.object.type == 'Car'
= render 'car_fields', :f => f
- elsif f.object.type == 'Truck'
= render 'truck_fields', :f => f
car_fields
and truck_fields
would also feature a link link_to_remove_association
provided by cocoon
Take a look at :wrap_object
documentation at https://github.com/nathanvda/cocoon , or read my blog post at http://www.powpark.com/blog/programming/2014/05/07/rails_nested_forms_for_single_table_inheritance_associations
Upvotes: 1
Reputation: 5336
I don't think that a simple select element on the form is the solution to your problem. What you are trying to achieve here is called Multiple Table Inheritance
and your problem should be the way you must structure your models in order be easily reflected on the database. Because it is a long discussion I will point you to this article where I explain the optimal way of doing this. I hope I helped you in a way :)
PS: To answer your question, no there is no built-in mechanism of doing that kind of thing in the Rails framework.
Upvotes: 0
Reputation: 10769
I might be wrong, but I understand polymorphic
as the other way around. I mean, a model can belong to more than one other model...
Car
and Truck
is a kind of Vehicle
. So, lets say that Vehicle
has year
and mark
attributes.
You are able to create a new Car
or Truck
, and having the polymorphic defined, you will create your form as usual.
@car = Car.find(id)
@vehicle = @car.vehicles.build(year: "1999", mark: "Beetle")
@vehicle.save
I hope it helps...
Upvotes: 0