Per this pull request I can see that an array should be passed to form_with
's model param. However, when I supply the following:
<%= form_with(model: [@trip, @activity], local: true) do |f| %>
...
<% end %>
Rails will return - ActionView::Template::Error (undefined method activity_path' for #<#<Class:0x007f80231e3070>:0x007f8023010dd8>):
My routes file looks like:
resources :trips do
resources :activities
end
The output of rake routes
looks like -
trip_activities GET /trips/:trip_id/activities(.:format) activities#index
POST /trips/:trip_id/activities(.:format) activities#create
new_trip_activity GET /trips/:trip_id/activities/new(.:format) activities#new
edit_trip_activity GET /trips/:trip_id/activities/:id/edit(.:format) activities#edit
trip_activity GET /trips/:trip_id/activities/:id(.:format) activities#show
PATCH /trips/:trip_id/activities/:id(.:format) activities#update
PUT /trips/:trip_id/activities/:id(.:format) activities#update
DELETE /trips/:trip_id/activities/:id(.:format) activities#destroy
trips GET /trips(.:format) trips#index
POST /trips(.:format) trips#create
new_trip GET /trips/new(.:format) trips#new
edit_trip GET /trips/:id/edit(.:format) trips#edit
trip GET /trips/:id(.:format) trips#show
PATCH /trips/:id(.:format) trips#update
PUT /trips/:id(.:format) trips#update
DELETE /trips/:id(.:format) trips#destroy
And my activities_controller.rb -
before_action :set_activity, only: %i[show update edit destroy]
def edit; end
def update
dates = calculate_datetimes(params[:date_range])
@activity.assign_attributes(name: params[:name],
summary: params[:summary],
start_datetime: dates[0],
end_datetime: dates[1])
if @activity.save
flash[:success] = 'Activity successfully updated'
redirect_to(@trip)
else
set_humanized_daterange
render :edit
end
end
private
def set_activity
@activity = Activity.find(params[:id])
end
tl;dr - how should I setup my form_with for a nested resource, and why is this form thinking I want to use the activity_path
? Ideally I'd like to move this form into a partial and use the same form for both my #new and #edit actions.
Try specifying the model and url separately:
form_with(model: @activity, url: [@trip, @activity])
According the docs the the values for url
are "Akin to values passed to url_for or link_to" so using an array should work.
This also works with shallow nesting since the array is compacted.
You just need to add the url to the route you want the form to point to, ie: , url: trip_activity_path
or whatever the path you are hitting is
Adding to max answer, if you want to support shallow nesting you can also use:
form_with(model: [@trip, @activity])
And change the render on your edit.html.erb to pass nil to trip, like:
<%= render 'form', trip: nil, activity: @activity %>
and keep it passing the trip model in your new.html.erb
Changing the url is fine, but you can instead change the model which allows the builder to infer the url and any scoping etc:
<%= form_with(model: child.new_record? ? [@parent, child] : child, local: true) do |form| %>
new/edit views: <%= render 'form', child: @child %>
controllers will need to set @parent from url params, which is convention for nested resources anyway.
来源:https://stackoverflow.com/questions/46919115/nested-resources-w-rails-5-1-form-with