35

I'm having trouble getting a has_many :through association working with Rails 4's strong parameters. I have a model called Checkout and I need to select a person from the Employee model in the new checkout form. Checkouts and Employees are associated through an Employment model.

I'm getting this error when I try to create a new checkout:

NoMethodError in CheckoutsController#create
undefined method `employee' for #<Checkout:0x007ff4f8d07f88>

It seems that there's something wrong with either my create action, my checkout parameters or my new checkout form. Here's the create action:

  def create    
    @user = current_user
    @checkout = @user.checkouts.build(checkout_params)

    respond_to do |format|
      if @checkout.save
        format.html { redirect_to @checkout, notice: 'Checkout was successfully created.' }
      else
        format.html { render action: 'new' }
      end
    end
  end

My checkout params:

def checkout_params
      params.require(:checkout).permit(:job, :employee_ids, :shift, :date, :hours, :sales, :tips, :owed, :collected, :notes)
end

My new checkout form:

<div class="field">
     <%= f.label :employee %><br>
     <%= f.collection_select(:employee_ids, Employee.all.collect, :id, :full_name, {:prompt => "Please select"} ) %>
</div>

But I can't figure out what has changed with Rails 4 and strong parameters. In Rails 3 this type of association and form worked for me using attr_accessible instead of strong_parameters.

Relevant Files

Full Trace of the error: https://gist.github.com/leemcalilly/0cb9e2b539f9e1925a3d

models/checkout.rb: https://gist.github.com/leemcalilly/012d6eae6b207beb147a

controllers/checkouts_controller.rb: https://gist.github.com/leemcalilly/a47466504b7783b31773

views/checkouts/_form.html.erb https://gist.github.com/leemcalilly/ce0b4049b23e3d431f55

models/employee.rb: https://gist.github.com/leemcalilly/46150bee3e6216fa29d1

controllers/employees_controller.rb: https://gist.github.com/leemcalilly/04f3acdac0c9a678bca8

models/employment.rb: https://gist.github.com/leemcalilly/6adad966dd48cb9d1b39

db/schema.rb: https://gist.github.com/leemcalilly/36be318c677bad75b211

Lee McAlilly
  • 9,084
  • 12
  • 60
  • 94
  • Having the same problem. I think the issue is that instead of just submitting the employee id, collection select wraps it in a hash. in your case "employee_ids"=>{"employee_id"=>"1","employee_id"=>"1"}. i bet if you check your log, there will be a line that says "Unpermitted parameters:employee_ids" or similar. – ctilley79 Jul 03 '13 at 02:11
  • I think that's the right direction. Here's my development log: https://gist.github.com/leemcalilly/cc2a71bef9a1e14fc5e6 Now how to fix this? – Lee McAlilly Jul 03 '13 at 20:05
  • I updated my checkout_params to this https://gist.github.com/leemcalilly/a71981da605187d46d96, and now I am getting an `Unpermitted parameters` as you can see here: https://gist.github.com/leemcalilly/ef0a58695b7318f068ab – Lee McAlilly Jul 03 '13 at 20:15

3 Answers3

55

Keep in mind that the name you give to your strong parameters (employees, employee_ids, etc.) is largely irrelevant because it depends on the name you choose to submit. Strong parameters work no "magic" based upon naming conventions.

The reason https://gist.github.com/leemcalilly/a71981da605187d46d96 is throwing an "Unpermitted parameter" error on 'employee_ids' is because it is expecting an array of scalar values, per https://github.com/rails/strong_parameters#nested-parameters, not just a scalar value.

# If instead of:
... "employee_ids" => "1" ...
# You had:
... "employee_ids" => ["1"]

Then your strong parameters would work, specifically:

... { :employee_ids => [] } ...

Because it is receiving an array of scalar values instead of just a scalar value.

Denzel
  • 936
  • 7
  • 6
4

Ok, so I actually did not need to nest the parameters. This is what ended up working for me:

# Never trust parameters from the scary internet, only allow the white list through.
def checkout_params
  params.require(:checkout).permit(:job, :shift, :employee_ids, :date, :hours, :sales, :tips, :owed, :collected, :notes)
end

Here is the combination of changes that worked.

Still not quite understanding why this worked though.

Lee McAlilly
  • 9,084
  • 12
  • 60
  • 94
  • Because you're not submitting a list of IDs...please refer to my previous explanation. – Denzel Jul 09 '13 at 12:39
  • Oh so at the beginning of this thread I was attempting to submit `:employee_id` when it should have been `:employee_ids`. I never needed to nest the attributes, right? – Lee McAlilly Jul 09 '13 at 13:09
  • 1
    Correct, naming aside, you never needed to nest the attributes since you were only submitting one scalar value. – Denzel Jul 10 '13 at 04:21
0

I can post the permit statement I use in one of my controllers. This has a many to many association as well. You nest the permit array. Use the lookup association in your permit statement. The only difference should be that yours won't be nested a third time.

In my case, the association Quote has_many :quote_items.

QuoteItems has_many :quote_options, :through => quote_item_quote_options.

In quotes_controller.rb

params.require(:quote).permit(:quote_date, :good_through, :quote_number, quote_items_attributes: [:id,:quote_id, :item_name, :material_id, quote_item_quote_options_attributes:[:quote_option_id,:quote_item_id,:qty,:_destroy,:id]])
ctilley79
  • 2,151
  • 3
  • 31
  • 64
  • Ok, based on that it seems that this should work for me `params.require(:checkout).permit(:job, :shift, :date, :hours, :sales, :tips, :owed, :collected, :notes, employees_attributes: [:id, :first_name, :last_name, :number ])`, but I'm still getting an `undefined method "employee"` error. I've tried all of these variations, but still get that error: https://gist.github.com/leemcalilly/91ab475cf2a9e819724e. Based on the strong params documentation https://github.com/rails/strong_parameters#nested-parameters, it seems like I could just use `{:employees => []}`, but that doesn't work either. – Lee McAlilly Jul 08 '13 at 13:33