2

I followed the Railscast for editing multiple records at the same time in one form. linked here: http://railscasts.com/episodes/165-edit-multiple-revised

This worked great for editing multiple onboarding_steps on the same form modal. Basically we mark the completion date of each step and hit save.

But now, one of these steps has a checklist of things to collect before it can be completed, and they want to put the checklist on the same form. And once I added in the <%= f.fields_for :onboarding_checkbox, onboarding_step.onboarding_checkbox do |checkboxes_form| %> section the form broke and threw a No route matches [POST] because the form is supposed to use PUT. For some reason adding in the nested attributes makes it want to do a POST instead of PUT.

This is it working properly before the nested attributes were added:

Started PUT "/onboarding_steps/update_multiple" for ::1 at 2018-06-15 15:25:25 -0500
Processing by OnboardingStepsController#update_multiple as HTML
  Parameters: {"utf8"=>"✓", "authenticity_token"=>"", 
"onboarding_steps"=>{"531"=>{"completed_date"=>""}, "280"=>{"completed_date"=>"02/09/2018"}}}, "commit"=>"Update"}

This is what it's doing with the nested section:

Invalid or incomplete POST params

Started POST "/onboarding_steps/update_multiple" for ::1 at 2018-06-15 15:47:08 -0500

ActionController::RoutingError (No route matches [POST] "/onboarding_steps/update_multiple"):

_edit_multiple.html.erb

<%= form_for :onboarding_steps, :url => update_multiple_onboarding_steps_path, :html => {:method => :put} do |form| %>
...
<% @onboarding_steps.each do |onboarding_step| %>
<%= fields_for "onboarding_steps[]", onboarding_step do |f| %>
... this is where it breaks the form ...
<% if onboarding_step.onboarding_checkbox.present? %>
<%= f.fields_for :onboarding_checkbox, onboarding_step.onboarding_checkbox do |checkboxes_form| %>
<%= submit_tag "Update", :class=>"btn btn-small btn-primary" %>

onboarding_steps_controller.rb

def edit_multiple
  onboarding_step = OnboardingStep.find(params[:onboarding_step_id])
  @onboarding_steps = OnboardingStep.includes(:onboarding_step_type).find(onboarding_step.group_steps.ids)
end

def update_multiple
  logger.debug params
  params.permit!
  @onboarding_steps = OnboardingStep.update(params[:onboarding_steps].keys, params[:onboarding_steps].values)
  @onboarding_steps.reject! { |s| s.errors.empty? }
  if @onboarding_steps.empty?
    redirect_to :back, notice: 'Update Successful'
  else
    render "edit_multiple"
  end
end

which at the bottom does include onboarding_checkbox_attributes:[]

onboarding_step.rb has accepts_nested_attributes_for :onboarding_checkbox

routes.rb

resources :onboarding_steps do
  resources :onboarding_checkboxes
  member do
    get "delete"
  end
  collection do
    get :edit_multiple
    put :update_multiple
  end
end

Not sure where it's going wrong. It's Friday and my brain is fried

3 Answers3

1

Had this same issue. Got around it by using each_with_index and assign an index to the record set:

In other words, instead of doing this:

<% @onboarding_steps.each do |onboarding_step| %>
<%= fields_for "onboarding_steps[]", onboarding_step do |f| %>

do this:

<% @onboarding_steps.each_with_index do |onboarding_step, index| %>
<%= fields_for "onboarding_steps[#{index}]", onboarding_step do |f| %>
rip747
  • 9,375
  • 8
  • 36
  • 47
0

Do not forget to include id in onboarding_checkbox_attributes:[]

seethrough
  • 712
  • 4
  • 15
0

I struggled with a very similar problem for a couple hours today. I think your issue is in:

f.fields_for :onboarding_checkbox

The error message, and resulting title of this question, is very misleading due to the way Rails handles PUT and PATCH requests. It says:

Invalid or incomplete POST params
Started POST "/update_multiple_objects" for ::1 at 2023-06-26 02:53:35 -0700

ActionController::RoutingError (No route matches [POST] "/update_multiple_objects"):

The key is in the first line: "Invalid or incomplete POST params". Because most browsers don't support PUT or PATCH requests, Rails Fudges it with a post request and a hidden "_method" input tag. I bet if you go into your HTML, that _method tag will still be present in your form. The issue is that you are passing "Invalid or Incomplete POST params", which causes rails to throw the POST error, even though you are "correctly" trying a PATCH.

Now, why are your POST params invalid or incomplete? When I went to look at the HTML form output, I noted that fields_for each "onboarding_step" would be correctly coded with the ID, e.g.

<input ... name="onboarding_step[203][some_attribute]" 

where "203" is the id of that object. BUT, if you look at the fields for the nested object, :onboarding_checkbox, you will note that it is wrapped with

<input ... name="onboarding_step[][onboarding_checkbox]

The id is missing!! Eventually, I actually figured it out by looking at this Question, and I realized Rails was expecting a pluralized option, even with a belongs_to (i.e. singular) association!

In my case, when I pluralized the object in my nested fields_for, it worked! Notably, the HTML started correctly wrapping the object id in the tags. So I suggest you try: f.fields_for :onboarding_checkboxes instead of the singular.

PS: I know this question is very stale - just posting this answer here for future reference of anyone else who stumbles on this issue.

PPS: this may not completely solve your problem. There are nuances to trying to do this through a belongs_to relationship, and at one point it wasn't possible at all (that post contains some workarounds)! However, it should be fixed with some adaptations as of Rails 4 and 5.

Nick Gobin
  • 131
  • 13