Unpermitted parameter is displayed when I try to create new data.
Althogh there are many similar questions, I can't find out how to solve.
What I'd like to do is to save the value in the amounts table when create schedule.
log
Processing by SchedulesController#create as HTML
Parameters: {"utf8"=>"?", "authenticity_token"=>"xxx", "schedule"=>{"title"=>"test title", "departure_date"=>"2016-07-06", "rooms_attributes"=>{"0"=>{"schedule_id"=>"", "amounts_attributes"=>{"0"=>{"schedule_id"=>"", "room_id"=>""}}}}}, "commit"=>"Create my schedule"}
Parameters: {"utf8"=>"?", "authenticity_token"=>"xxx", "schedule"=>{"title"=>"test title", "departure_date"=>"2016-07-06", "rooms_attributes"=>{"0"=>{"schedule_id"=>"", "amounts_attributes"=>{"0"=>{"schedule_id"=>"", "room_id"=>""}}}}}, "commit"=>"Create my schedule"}
User Load (120.7ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", 1]]
User Load (120.7ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", 1]]
Unpermitted parameter: amounts_attributes
models
schedule.rb
class Schedule < ActiveRecord::Base
belongs_to :user
has_many :rooms, inverse_of: :schedule, dependent: :destroy
has_many :amounts, inverse_of: :schedule, dependent: :destroy
accepts_nested_attributes_for :rooms, allow_destroy: true
accepts_nested_attributes_for :amounts, allow_destroy: true
rooms.rb
class Room < ActiveRecord::Base
belongs_to :schedule, inverse_of: :rooms
has_many :events, inverse_of: :room, dependent: :destroy
has_many :amounts, inverse_of: :room, dependent: :destroy
accepts_nested_attributes_for :events, allow_destroy: true
accepts_nested_attributes_for :amounts, allow_destroy: true
amount.rb
class Amount < ActiveRecord::Base
belongs_to :schedule, inverse_of: :amounts
belongs_to :room, inverse_of: :amounts
belongs_to :event, inverse_of: :amounts
end
controller
schedule_controller.rb
def new
#schedule = Schedule.new
room = #schedule.rooms.build
room.amounts.build
end
def create
#schedule = current_user.schedules.build(schedule_params)
if #schedule.save
flash[:success] = "schedule created!"
redirect_to schedule_path(#schedule)
else
render 'new'
end
end
...
def schedule_params
params.require(:schedule).permit(
:title, :departure_date,
rooms_attributes: [
:id, :_destroy, :room, :room_address, :schedule_id, :day,
amounts_attributes: [
:schedule_id, :room_id, :event_id, :id, :_destroy, :ccy, :amount
]
]
)
end
view
/schedules/new.html.erb
...
<%= form_for(#schedule) do |f| %>
<%= render 'schedule_form', f: f %>
<%= f.submit "Create my schedule", class: "btn btn-primary" %>
...
/schedules/ _schedule_form.html.erb
It works before adding 4 lines for <%= room.fields_for(:amounts) do |amount| %>.
...
<%= f.label :title %>
<%= f.text_field :title, class: 'form-control' %>
...
<%= f.fields_for(:rooms) do |room| %>
<%= room.hidden_field :schedule_id %>
<%= room.fields_for(:amounts) do |amount| %> # my app works before add these 4 lines.
<%= amount.hidden_field :schedule_id %> #
<%= amount.hidden_field :room_id %> #
<% end %> #
<% end %>
It would be appreciated if you could give me any suggestion.
You haven't closed the room_attributes array parameter.Please close it and open the amount's attribute nested parameters. Also the schedule_id in amount's attributes.
def schedule_params
params.require(:schedule).permit(:title,
:departure_date,{rooms_attributes: [:id, :_destroy, :room, :room_address, :schedule_id, :day,
{ amounts_attributes: [:itinerary_id, :room_id, :event_id, :id, :_destroy, :ccy, :amount]}
]}
)
end
Following from the logged params, your amounts_attributes is an array of objects and should be declared as such in your permit method argument:
def schedule_params
params.require(:schedule).permit(
:title, :departure_date,
rooms_attributes: [{
:id, :_destroy, :room, :room_address, :schedule_id, :day,
amounts_attributes: [{
:itinerary_id, :room_id, :event_id, :id, :_destroy, :ccy, :amount
}]
}]
)
end
The rooms_attributes follows similar structure and needs to be corrected as well.
Take a look at the nested parameters example in ActionController::Parameters docs.
I think your params should look like this:
def schedule_params
params.require(:schedule).permit(
:title, :departure_date,
rooms_attributes: [
:id, :_destroy, :room, :room_address, :schedule_id, :day,
amounts_attributes: [ :id, :_destroy,
:itinerary_id, :room_id, :event_id, :id, :_destroy, :ccy, :amount]
]
)
end
So, for your nested model, even if it's deeply nested, you still need :id and :_destroy.
Let me know how that goes for you.
Related
I am learning rails and will be very grateful for an advice about creating a form object with multiple input fields with the same name. I am having errors with unpermitted params.
I've been searching information for several days, have tried a lot without any result. This is my first question, sorry if it is not easy to understand.
I am using rails 6.0.0, and having 3 models: Recipe, Ingredient, RecipeIngredientRelation. I want to make multiple input fields for Ingredient and RecipesIngredient. Errors:
Parameters: {"authenticity_token"=>"G6vwDdptMBgl2SPvLfS4BoiCjoRnf+FGYuKW0Ykt3Aodt5HfBEx5KHWBEpl4r52ANCv9QWz13rDyAP42qCyESg==", "recipes_ingredient"=>{"name"=>"Recipe", "portions"=>"1", "time_count_id"=>"3", "calories"=>"", "ingredients"=>{"i_name"=>"water"}, "recipe_ingredient_relations"=>{"quantity"=>["100"], "measurement_id"=>"3"}, "recipe"=>"some text", "tips"=>"", "is_public"=>"0"}, "commit"=>"レシピを投稿する"}
Unpermitted parameters: :ingredients, :recipe_ingredient_relations
binding.pry gets me #recipes_ingredient.errors:
#details={:i_name=>[{:error=>:blank}]},
#messages={:i_name=>["can't be blank"]}>
my models are:
Recipe
has_many :recipe_ingredient_relations
has_many :ingredients, through: :recipe_ingredient_relations
accepts_nested_attributes_for :ingredients, :recipe_ingredient_relations, allow_destroy: true
Ingredient
has_many :recipe_ingredient_relations
has_many :recipes, through: :recipe_ingredient_relations
RecipeIngredientRelation
belongs_to :recipe
belongs_to :ingredient
Form Object
class RecipesIngredient
include ActiveModel::Model
attr_accessor :ingredients, :i_name, :recipe_ingredient_relations, :quantity, :measurement_id, :name, :image, :portions, :time_count_id, :recipe, :tips, :calories, :is_public, :user_id
with_options presence: true do
validates :i_name #, uniqueness: true
validates :quantity, length:{maximum: 10}, allow_blank: true
validates :measurement_id, allow_blank: true
validates :name
validates :portions
validates :time_count_id, numericality: {other_than: 1}
validates :recipe
validates :tips, allow_blank: true
validates :calories, allow_blank: true
validates :is_public
end
def save
recipe = Recipe.create(user_id: user_id, name: name, image: image, portions: portions, time_count_id: time_count_id, recipe: recipe, tips: tips, calories: calories, is_public: is_public)
ingredient = Ingredient.create(i_name: i_name)
recipe_ingredient_relation = RecipeIngredientRelation.create(recipe_id: recipe.id, ingredient_id: ingredient.id, quantity: quantity, measurement_id: measurement_id)
end
end
part of input form view:
%= form_with(model: #recipes_ingredient, url:recipes_path, local: true) do |form| %>
<...>
<%= form.fields_for :ingredients do |f| %>
<%= f.text_field :i_name, placeholder: "例)レタス", class: "form-el ingredient-input required" %>
<% end %>
<%= form.fields_for :recipe_ingredient_relations do |f| %>
<div class="quantity">
<%= f.text_field :quantity, multiple: true, placeholder: "例)100", class: "form-el quantity-input required" %>
<%= f.collection_select(:measurement_id, Measurement.all, :id, :name, {}, {class:"after-input-required"}) %>
<p class="after-input after-input-btn-required">+</p>
</div>
</div>
<% end %>
and, finally, the Recipes controller:
class RecipesController < ApplicationController
def index
#recipe = Recipe.all
end
def new
#recipes_ingredient = RecipesIngredient.new
end
def create
#recipes_ingredient = RecipesIngredient.new(recipe_params)
binding.pry
# if #recipe.valid?
# #recipe.save
# redirect_to root_path
# else
# render action: :new
# end
end
private
def recipe_params
params.require(:recipes_ingredient).permit(:name, :image, :portions, :time_count_id, :recipe, :tips, :calories, :is_public, ingredients_attributes: [:id, :i_name], recipe_ingredient_relations_attributes: [:id, :quantity, :measurement_id] ).merge(user_id: current_user.id)
end
end
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?
I knew it was something simple. This takes care of the whole problem.
params.require(:menu).permit(:user_id, :name, :description, { :recipe_ids => [] } )
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.
I'm having almost exactly the same problem as here:
Rails has_many :through saving additional fields
However I can't figure out what's missing in my code. The basic structure is following: there are Products and they may have additional services (like cleaning or sharpening). The basic price for each service is same, however products may have different coefficients. Let's say, Product 1 may have sharpening basic price * 1.5 and Product 2 may have sharpening basic price * 2. The join table is called somewhat stupid - servization, I couldn't figure out a decent name.
products_controller.rb:
def update
#product.update!(product_params)
redirect_to #product
end
def product_params
params.require(:product).permit(
:title, :description, :advertising_text, :fancy_quote, :hot, :hotpic, :product_size_ids,
{ volume_ids: [] }, { color_ids: [] }, { addservice_ids: [] }, :category_id, :subcategory_id,
options_attributes: [:size, :weight, :price, :material, :product_id],
images_attributes: [ :image, :product_id ],
servizations_attributes: [:coefficient, :product_id, :addservice_id]
)
end
product model (i cut out the irrelevant parts) :
class Product < ActiveRecord::Base
has_many :servizations
has_many :addservices, through: :servizations
accepts_nested_attributes_for :servizations
before_destroy :ensure_not_referenced_by_any_line_item
end
additional service model:
class Addservice < ActiveRecord::Base
has_many :servizations
has_many :products, through: :servizations
end
servization model
class Servization < ActiveRecord::Base
belongs_to :product
belongs_to :addservice
end
Here is my edit.html.haml:
=form_for #product do |f|
=f.label 'Title'
=f.text_field :title
%p
=f.label 'Colors'
=collection_check_boxes(:product, :color_ids, Color.all, :id, :value )
%p
=f.label 'Additional services'
=collection_check_boxes(:product, :addservice_ids, Addservice.all, :id, :title)
=f.fields_for :servization do |s|
=s.label 'Coefficient'
=s.text_field :coefficient
%p
=f.submit class: 'btn btn-default'
I have no issues saving plain services or just the colors, however when I try to edit and save the coefficient, then I receive following error:
Processing by ProductsController#update as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"jLN59PIOgpaIQtg2/rVYcK/xUOCFzSMLosfUhOslY9tNNhjFbh16Aa1/qT/8u7LHuhNTLGr2SB7b/BitekuDJQ==", "product"=>{"title"=>"Power MI", "color_ids"=>["1", "2", "3", ""], "addservice_ids"=>["1", ""], "servization"=>{"coefficient"=>"1.5"}}, "commit"=>"Update Product", "id"=>"7"}
Product Load (0.3ms) SELECT "products".* FROM "products" WHERE "products"."id" = $1 LIMIT 1 [["id", 7]]
Unpermitted parameter: servization
Servization structure:
Servization(id: integer, product_id: integer, addservice_id: integer, coefficient: float, created_at: datetime, updated_at: datetime)
I don't get it... my options are saved well, images too. But additional services refuse to save.
Edit 1:
I think I might be close to the solution. The problem is the correct linking in the form. This is what I came up with so far:
=form_for #product do |f|
%p
=f.label "Additional Services"
%br
-Addservice.all.each do |addservice|
=check_box_tag "product[addservice_ids][]", addservice.id, #product.addservice_ids.include?(addservice.id)
=addservice.title
=text_field_tag "product[servizations][coefficient][]", addservice.servizations.where(product_id: #product.id)[0].coefficient
%br
%p
=f.submit class: 'btn btn-default'
This is the patch request:
Parameters: {"utf8"=>"✓", "authenticity_token"=>"wD8uMSu0TxvumAWcs1V6GtAFeNgYhbEPEh8HuV8RWucBuk8At6e3jMuldJWxW5Ctxed7FPe+2hprJMuQzn+6GQ==", "product"=>{"title"=>"Флешеченка на тристапяцот гигов", "color_ids"=>["1", "2", "3", ""], "addservice_ids"=>["1", "2"], "servizations"=>{"coefficient"=>["4", "5"]}}, "commit"=>"Update Product", "id"=>"5"}
However now I'm getting again
Unpermitted parameter: servizations
Error
The problem is here in this line
=f.fields_for :servization do |s|
which should be
=f.fields_for :servizations do |s|
Update:
You should permit :id for update to work correctly
def product_params
params.require(:product).permit(
:title, :description, :advertising_text, :fancy_quote, :hot, :hotpic, :product_size_ids,
{ volume_ids: [] }, { color_ids: [] }, { addservice_ids: [] }, :category_id, :subcategory_id,
options_attributes: [:size, :weight, :price, :material, :product_id],
images_attributes: [ :image, :product_id ],
servizations_attributes: [:id, :coefficient, :product_id, :addservice_id]
)
end
I've followed Cocoon's instructions for creating a nested form for a has_many association but there's one thing that I can't seem to figure out. I'm able to add an existing genre to my project but when it comes to creating a completely new one the parameters for my genres aren't being permitted. When I refer to my rails console to debug the issue this is the message I receive upon update:
Unpermitted parameters: genre_attributes
What's strange is I've permitted both my join table genreships and my genre model along with having my movie model accept their nested attributes but still no luck. There has to be something I'm not doing in my movie_params method but not able to find what. I've literally tried to permit every possible attribute within this method and completely out of ideas on what could be the solution
Models
class Movie < ActiveRecord::Base
has_many :genreships
has_many :genres, through: :genreships
accepts_nested_attributes_for :genres, :reject_if => :all_blank, :allow_destroy => true
accepts_nested_attributes_for :genreships, :reject_if => :all_blank, :allow_destroy => true
extend FriendlyId
friendly_id :title, use: :slugged
end
class Genreship < ActiveRecord::Base
belongs_to :movie
belongs_to :genre
accepts_nested_attributes_for :genre, :reject_if => :all_blank
end
class Genre < ActiveRecord::Base
has_many :genreships
has_many :movies, through: :genreships
extend FriendlyId
friendly_id :name, use: :slugged
end
Movies Controller
def movie_params
params.require(:movie).permit(:title, :release_date, :summary, genreships_attributes: [:id, :genre_id, :_destroy], genres_attributes: [:id, :_destroy, :name])
end
Form
= simple_form_for #movie do |f|
.field
= f.input :title
.field
= f.input :release_date, label: 'Release Date', order: [:month, :day, :year], start_year: 1901
.field
= f.input :summary, as: :text
#genres
= f.simple_fields_for :genreships do |genreship|
= render 'genreship_fields', :f => genreship
= link_to_add_association 'add a genre', f, :genreships
.actions = f.submit 'Save', class: 'btn btn-default'
Genreship Partial
.nested-fields
#genre_from_list
= f.association :genre, :collection => Genre.order(:name), :prompt => 'Choose an existing genre'
= link_to_add_association 'or create a new genre', f, :genre
= link_to_remove_association "remove genre", f
Genre Partial
.nested-fields
= f.input :name
Here's what's shown in the rails console right after posting a new movie:
Started POST "/movies" for 127.0.0.1 at 2014-11-19 08:17:42 -0500
Processing by MoviesController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"2/wqXhn/x73AdOOrSo49Q/OPAmrcVk0rLViJJNpIhps=", "movie"=>{"title"=>"", "release_date(2i)"=>"11", "release_date(3i)"=>"19", "release_date(1i)"=>"2014", "summary"=>"", "genreships_attributes"=>{"1416403056574"=>{"genre_attributes"=>{"name"=>"Comedy"}, "genre_id"=>"", "_destroy"=>"false"}}}, "commit"=>"Save"}
Unpermitted parameters: genre_attributes
You use genre_attributes while genres_attributes (plural form) is defined in your controller. Change it to:
def movie_params
params.require(:movie).permit(:title, :release_date, :summary, genreships_attributes: [:id, :genre_id, :_destroy], genre_attributes: [:id, :_destroy, :name])
end
I created a solution that in a sense deviates from Nathan's example code somewhat but gets the job done nonetheless. Simply moving this line from genreship_fields.html.slim to _form.html.slim did the trick:
link_to_add_association 'create a new genre', f, :genres
My partials now look like this:
Form
= simple_form_for #movie do |f|
.field
= f.input :title
.field
= f.input :release_date, label: 'Release Date', order: [:month, :day, :year], start_year: 1901
.field
= f.input :summary, as: :text
#genres
= f.simple_fields_for :genreships do |genreship|
= render 'genreship_fields', :f => genreship
| #{link_to_add_association 'add a genre', f, :genreships} | #{link_to_add_association 'create a new genre', f, :genres}
.actions = f.submit 'Save', class: 'btn btn-default'
Genreship Partial
.nested-fields
#genre_from_list
= f.association :genre, :collection => Genre.order(:name), :prompt => 'Choose an existing genre'
= link_to_remove_association "remove genre", f
Genre Partial
.nested-fields
= f.input :name
= link_to_remove_association "remove form", f
I have models
class Profile < ActiveRecord::Base
belongs_to :user
has_many :user_interests
has_many :interests, :through => :user_interests
accepts_nested_attributes_for :user_interests
end
class UserInterest < ActiveRecord::Base
belongs_to :profile
belongs_to :interest
end
class Interest < ActiveRecord::Base
has_many :user_interests
has_many :profiles, :through => :user_interests
end
controller
private
def profile_params
params.require(:profile).permit(:first_name, :last_name, :date_of_birth, user_interests_attributes: {:interest => []})
end
view
=#"http://stackoverflow.com/questions/18428871/multi-column-forms-with-fieldsets"
= simple_form_for(#profile, html: {class: 'form-horizontal'}) do |f|
.well.well-lg
%fieldset
%legend Personal Information
.row
.col-sm-4
.form-group
= f.input :first_name, label: 'First Name*'
= f.hint 'No special characters, please!'
.col-sm-4
.form-group
= f.input :last_name, label: 'First Name*'
= f.hint 'No special characters, please!'
.row
.col-sm-4
.form-group
= f.input :date_of_birth, as: :string, 'data-behaviour'=>'datepicker'
%legend Other Information
.row
.col-sm-4
.form-group
= f.simple_fields_for :user_interests, UserInterest.new do |s|
= s.collection_select(:interest, Interest.all, :id, :name,{},{:multiple=>true})
= f.hint 'Please use Ctrl key on your keyboard to select multiple items'
.row
= f.submit
But getting error unpermitted parameters
profile_params
Unpermitted parameters: interest
=> {"first_name"=>"", "last_name"=>"", "date_of_birth"=>"", "user_interests_attributes"=>{"0"=>{}}}
where my params are:
params
=> {"utf8"=>"✓", "_method"=>"patch", "authenticity_token"=>"7/7sKljbi88cmUOen/WFWzhzV6exE8I8fBnNMA5EELw=",
"profile"=> {"first_name"=>"", "last_name"=>"",
"date_of_birth"=>"",
"user_interests_attributes"=>{"0"=>{"interest"=>"test"}}},
"commit"=>"Update Profile", "action"=>"update",
"controller"=>"profiles", "id"=>"1"}
Please correct me where I am wrong
You forgot to add accepts_nested_attributes_for :interest on UserInterest.
class Profile < ActiveRecord::Base
belongs_to :user
has_many :user_interests
has_many :interests, :through => :user_interests
accepts_nested_attributes_for :user_interests
end
class UserInterest < ActiveRecord::Base
belongs_to :profile
belongs_to :interest
accepts_nested_attributes_for :interest
end
class Interest < ActiveRecord::Base
has_many :user_interests
has_many :profiles, :through => :user_interests
end
You might have to define interest as a valid parameter on strong_parameters definition in your controller.