Michael
Michael

Reputation: 421

simple_form has_many through unpermitted parameters

I'm having a little trouble setting up my simple for for create/update. Here's the form:

<%= simple_form_for( setup_menu(@menu) ) do |f| %>

<%= f.input :user_id, :as => :hidden %>
<%= f.input :name %>
<%= f.input :description %>

<%= f.association :recipes %>

<%= f.button :submit %>
<% end %>

Here are the three models:

class Menu < ActiveRecord::Base
  has_many :courses
  has_many :recipes, through: :courses

  accepts_nested_attributes_for :recipes,
    reject_if: :all_blank

  accepts_nested_attributes_for :courses,
    reject_if: :all_blank
end
class Recipe < ActiveRecord::Base
  has_many :courses
  has_many :menus, through: :courses

  accepts_nested_attributes_for :menus 
end
class Course < ActiveRecord::Base
    belongs_to  :menu
    belongs_to  :recipe
end

And here is the params definition from the menus_controller:

    def menu_params
      params.require(:menu).permit(:user_id, :name, :description, :recipe_ids, :course_ids, :courses, :recipes,
        recipes_attributes: [:id, :recipe_id, :_destroy],     courses_attributes: [:id, :recipe_id, :menu_id, :_destroy]
      )
    end

I keep getting an unpermitted parameter error on the recipe_ids.

Started PATCH "/menus/1" for ::1 at 2015-10-01 20:54:56 -0500
Processing by MenusController#update as HTML
  Parameters: {"utf8"=>"√", "authenticity_token"=>"i/7E27BWul9trszURDu1z8PtsHaG54byG9JOlEp3mn2oQZVveM2mSP4XTLzjWKAK+BNvwoi/pqBbQPrPTcnaDw==", "menu"=>{"name"=>"Menu 1", "description"=>"First test menu", "recipe_ids"=>["", "1", "3", "4"]}, "
commit"=>"Update Menu", "id"=>"1"}
  Menu Load (1.0ms)  SELECT  "menus".* FROM "menus" WHERE "menus"."id" = ? LIMIT 1  [["id", 1]]
Unpermitted parameter: recipe_ids
   (1.0ms)  begin transaction
   (0.0ms)  commit transaction
Redirected to http://localhost:3000/menus/1
Completed 302 Found in 11ms (ActiveRecord: 2.0ms)

I'm sure it is something simple I've missed. I have been scratching my head for a whole day on this. Can someone help?

Upvotes: 1

Views: 1655

Answers (2)

Richard Peck
Richard Peck

Reputation: 76774

To add to your answer, there are a bunch of issues with your structure.


Object

You're calling setup_menu in your view; this should at least be called in your controller (unless you're using a partial... even then it should be passed as a local var).

<%= simple_form_for @menu do |f| %>
   <%= f.hidden_field :user_id %>
   <%= f.input :name %>
   <%= f.input :description %>

   <%= f.association :recipes %>

   <%= f.button :submit %>
<% end %>

This has to be backed up with the appropriate controller action. Again, if you're using this in the likes of a partial, you'll be able to assign the action at the same time you're defining @menu:

#app/controllers/menus_controller.rb
class MenusController < ApplicationController
   def new
      @menu = setup_menu x
   end
end

Associative Data

Because you're using a has_many :recipes association, you should be able to set :recipes in your strong params. Failing that, your recipe_ids should be okay, but I think your encapsulation in parentheses is incorrect:

params.require(:menu).permit(:user_id, :name, :description, recipe_ids: [])

As an aside, if you had a has_and_belongs_to_many relationship set up, you'll be able to pass recipes as follows:

params.require(:menu).permit(:user, :name, :description, :recipes)

I see no reason why this would not work for your has_many :through


Definitions

Finally, you should be able to set multiple definitions in your model for accepts_nested_attributes_for:

#app/models/menu.rb
class Menu < ActiveRecord::Base
  has_many :courses
  has_many :recipes, through: :courses

  accepts_nested_attributes_for :recipes, :courses, reject_if: :all_blank
end

One of the most important, and simple, ways of keeping your code efficient is to make it readable. Above is an example of this - repeating yourself unnecessarily not only clutters your code, but prevents efficient management.

Upvotes: 1

Michael
Michael

Reputation: 421

I knew it was something simple. This takes care of the whole problem.

params.require(:menu).permit(:user_id, :name, :description, { :recipe_ids => [] } )

Upvotes: 1

Related Questions