I have a complex form for a model Schedule that belongs to a parent Listing model:
class Listing < ActiveRecord::Base
has_many :schedules, :dependent => :destroy
accepts_nested_attributes_for :schedules, :allow_destroy => true, :reject_if => :all_blank
...
end
class Schedule < ActiveRecord::Base
belongs_to :listing
...
end
Because of the complexity of the schedule form I do not want to display it for each item in the fields_for Schedules, so these only contain a title and a delete link (and a bunch of hidden fields for the other params).
Instead the complex form is used to asynchronously generate new form fields for each Schedule which are then inserted into the parent’s form. This is simply the response from the Schedule form being posted (using a partial _new_schedule_fields) which is appended to a fields_for(:schedules) section in the Listing form. The child Schedule(s) then get created automatically when the Listing is saved since it accepts_attributes_for Schedules. The call to the Schedule form looks like this (sits after the form_for Listings in the page):
form_for([@listing, @schedule], :remote => true) do |f|
This works very well when editing an existing Listing but the form_for used to build the complex Schedule form falls over on new Listings:
=> No route matches {:action=>"create", :controller=>"schedules")
In my routes I have (Rails 3):
resources :listings do
resources :schedules
end
This makes perfect sense of course, as the expected route would be /listings/:listing_id/schedules/new but I wonder if there is a way to use the form_for builder to generate a form for a nested model belonging to an unsaved parent? /listings/new/schedules/new seems absurd but perfectly sums up what I’m after!
Grateful for any helpful suggestions.
Edit:
I should add that I’m building new Schedule instances in the new and edit methods of the Listings controller, like so:
def new
@listing = Listing.new
@schedule = @listing.schedules.build
end
def edit
@listing = Listing.find(params[:id])
@schedule = @listing.schedules.build
end
You can’t use form_for by default to do an embedded object under a new parent, because there is no way for the controller to return an object that is the child of your new object, since you cannot assign the child to an object with no id. You would have to set up a custom route. Conceptually to me, though, the limitation makes sense – you’re NOT requesting the application to return a child of your new object, because you can’t make a child until you make the object, so you’d call the non-embedded route, just form_for(@schedule). Then, just return the whole build tree as one object, so that it all saves together. You have to embed it in the final save request, until that time, there IS no embedded object.