Unpermitted parameters: author - ruby-on-rails

My requirements
Basically I'm adding books to a database, and I want to store the Author in a separate table. So I have a table called authors which is referenced by the table books.
I want to create a rails form for adding a book, and I'd like it to be just a simple form for Author, Title, Publisher etc, and if it finds the author already in the authors table then it should just reference that record, and if it isn't in the authors table then it should add a new record and reference it.
while storing values i am getting in log file
Unpermitted parameters: author
Processing by BooksController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"8sxeOVMVJucl5nN+kMpSaT1cB1yDPnk5gfKElWPiT5k=", "book"=>{"book_name"=>"life ", "price"=>"20", "author"=>{"author_name"=>"swamy", "title"=>"LIFE", "publisher"=>"cta"}}, "commit"=>"Submit"}
swamy
LIFE
cta
Author Load (1.6ms) SELECT "authors".* FROM "authors" WHERE "authors"."author_name" = 'swamy' AND "authors"."title" = 'LIFE' AND "authors"."publisher" = 'cta' LIMIT 1
(0.6ms) BEGIN
SQL (25.2ms) INSERT INTO "authors" ("author_name", "created_at", "publisher", "title", "updated_at") VALUES ($1, $2, $3, $4, $5) RETURNING "id" [["author_name", "swamy"], ["created_at", "2015-07-01 03:53:22.712401"], ["publisher", "cta"], ["title", "LIFE"], ["updated_at", "2015-07-01 03:53:22.712401"]]
(16.8ms) COMMIT
Unpermitted parameters: author
(0.7ms) BEGIN
SQL (1.0ms) INSERT INTO "books" ("Author_id", "book_name", "created_at", "price", "updated_at") VALUES ($1, $2, $3, $4, $5) RETURNING "id" [["Author_id", 8], ["book_name", "life "], ["created_at", "2015-07-01 03:53:22.865106"], ["price", 20], ["updated_at", "2015-07-01 03:53:22.865106"]]
(22.4ms) COMMIT
my code
books_Controller
class BooksController < ApplicationController
def new
end
def create
#a=params[:author_name]
puts #a
b=params[:book][:author][:author_name]
puts b
# #c = #b.authors
# #d = #c.author_name
c=params[:book][:author][:title]
d=params[:book][:author][:publisher]
puts c
puts d
#author = Author.find_or_create_by(author_name: b,title: c, publisher: d)
#book = Book.new(books_params)
#book.Author = #author
#book.save
redirect_to root_url
end
private
def books_params
params.require(:book).permit(:book_name, :price,:author_attributes => [:author_name, :title, :publisher])
end
end
model
class Author < ActiveRecord::Base
end
class Book < ActiveRecord::Base
belongs_to :Author
accepts_nested_attributes_for :Author
# def author_name=(author_name)
# self.author = Author.find_or_create_by_name author_name
#end
end
view
books.html.erb
<%= form_for Book.new do |f| %>
<p>
<%= f.label :book_name %><br />
<%= f.text_field :book_name %>
</p>
<p>
<%= f.label :price %><br />
<%= f.text_field :price %>
</p>
<%= f.fields_for :author do |b| %>
<p>
<%= b.label :author_name%><br />
<%= b.text_field :author_name %>
</p>
<p>
<%= b.label :title%><br />
<%= b.text_field :title %>
</p>
<p>
<%= b.label :publisher%><br />
<%= b.text_field :publisher%>
</p>
<% end %>
<p><%= f.submit "Submit" %></p>
<% end %>
~
Hi sir i am new to rails i know it looks simple but i unable it find solution
~
~

That is because your books_params has author_attributes when it should be author based on your parameters.
This should work:
def books_params
params.require(:book).permit(:book_name, :price, :author => [:author_name, :title, :publisher])
end

Your code is full of errors. Follow my changes.
#book.rb
class Book < ActiveRecord::Base
belongs_to :author
accepts_nested_attributes_for :author
end
#books_controller.rb
def new
#book = Book.new
#book.build_author
end
def create
#book = Book.new(books_params)
if #book.save
redirect_to root_url
end
end
Finally in your form change <%= form_for Book.new do |f| %> to <%= form_for #book do |f| %>

Change authore to author_attributes in view file, like this.
<%= f.fields_for :author_attributes do |b| %>
<p>
<%= b.label :author_name%><br />
<%= b.text_field :author_name %>
</p>
Also change respectively in controller also. I think, this much is enough.
def create
#book = Book.new(books_params)
#book.save
redirect_to root_url
end

I will Suggested you just debug your code
def books_params
byebug
params.require(:book).permit(:book_name, :price, :author => [:author_name, :title, :publisher])
end
1: check your requested params
2: kindly check params.require(:book)
Requested parameter would be like
Parameters: {"utf8"=>"✓", "authenticity_token"=>"8sxeOVMVJucl5nN+kMpSaT1cB1yDPnk5gfKElWPiT5k=", "book"=>{"book_name"=>"life ", "price"=>"20", "author_"=>{"author_name"=>"swamy", "title"=>"LIFE", "publisher"=>"cta"}}, "commit"=>"Submit"}
check with this link NestedAttributes
Your controller would be this
class BooksController < ApplicationController
def new
end
def create
#author = Author.create(params[:book])
redirect_to root_url
end
private
def books_params
params.require(:book).permit(:book_name, :price,:author_attributes => [:author_name, :title, :publisher])
end
end

Related

Rails doesn't update nested attributes

I create an application, which is basically a character creator for an RPG with interactive and dynamic forms. I use Rails 5.0.0.1, and I cannot update my form properly. The base model updates well, but all nested don't.
So, I have
class Character < ApplicationRecord
has_many :attr4characters, autosave: true
accepts_nested_attributes_for :attr4characters, allow_destroy: true
end
and
class Attr4character < ApplicationRecord
belongs_to :character
end
which represent a character and a set of his attributes. Each record in Attr4character is a different attribute.
The Show view is simple:
...
<div class="field">
<%= f.label :description %>
<%= f.text_area :description %>
</div>
<div class="field">
<%= f.label :character_type %>
<%= f.select(:character_type, options_for_select(["Zhong Lung", "Shih", "Hsien", "Garou", "Technocrat"])) %>
</div>
<% f.object.attr4characters.each do |attr| %>
<%= f.fields_for attr do |attr_f| %>
<div class="field">
<%= attr_f.label "Field name" %>
<%= attr_f.text_field :field_name %>
</div>
<div class="field">
<%= attr_f.label "Field value" %>
<%= attr_f.text_field :field_value %>
</div>
<% end %>
<% end %>
<div class="actions">
<%= f.submit %>
</div>
...
And finally my characters_controller:
def update
respond_to do |format|
if #character.update(character_params)
format.html { redirect_to #character, notice: 'Character was successfully updated.' }
format.json { render :show, status: :ok, location: #character }
else
format.html { render :edit }
format.json { render json: #character.errors, status: :unprocessable_entity }
end
end
end
private
def set_character
#character = Character.find(params[:id])
end
def character_params
params.require(:character).permit(:id, :name, :player, :description, :character_type, attr4characters_attributes: [:id, :character_id, :field_name, :field_value])
end
So, I have a form, which correctly display a character and all set of his attributes. When I update a character field (like :description), it is normally updated. When I update any nested field, Rails says that character is successfully updated and nothing changes! I searched with Google, and I found a lot of problems with nested attributes in Rails forms, but none of the recipes worked for me. I even encountered opinions that it is a bug in Rails 4, but I use 5th version...
Please, advice on the topic. Is it a bug really? Or am I doing something wrong? I'm new on Rails, so I don't exclude that possibility. :)
By the way, in the server's log I found that there is warning about attr4characters.
Processing by CharactersController#update as HTML
Parameters: {"utf8"=>"\u2713", "authenticity_token"=>"xeYyIRc13YiOk29v18rFM6Oh5OHRRuPpSKEQuIHE/U4uhANEF7TwMp8mb6hv6L7mUAm5MngAuyFayHcWV/Vvbw==", "character"=>{"name"=>"Ray", "player"=>"111", "description"=>"A Zhong Lung suicider", "character_type"=>"Hsien", "attr4character"=>{"field_name"=>"Gift1", "field_value"=>"Sense Wyrm"}}, "commit"=>"Update Character", "id"=>"3"}
Character Load (0.2ms) SELECT "characters".* FROM "characters" WHERE "characters"."id" = ? LIMIT ? [["id", 3], ["LIMIT", 1]]
Unpermitted parameter: attr4character
(0.1ms) begin transaction
SQL (0.9ms) UPDATE "characters" SET "character_type" = ?, "updated_at" = ? WHERE "characters"."id" = ? [["character_type", "Hsien"], ["updated_at", 2016-09-13 14:39:10 UTC], ["id", 3]]
(24.3ms) commit transaction
But attr4characters are permitted in the characters_controller...
The warning is telling you that it is ignoring all the attr4character attributes. Your permit code is correct as is your model, but your view doesn't match them. You should be doing
f.fields_for :attr4characters do |attr_f|
...
end
And let rails handle iterating over the association. This will also ensure that attributes are named correctly (so they will be allowed through by your whitelist)

Rails 4 nested strong parameters throwing unpermited parameters error

I've been at this for hours now but can't figure it out:
Trying to create a new address in the new organisation form. An address can be created for an organisation, company or employee. I want the Address_id relevant to the Orgainsation/Company/Employee to be stored in their database record but can't get strong_parameters to work properly.
models/organisation.rb
class Organisation < ActiveRecord::Base
belongs_to :address
has_many :users
accepts_nested_attributes_for :address
end
models/address.rb
class Address < ActiveRecord::Base
has_many :organisations
has_many :companies
has_many :employees
end
views/organisations/_form.html.erb
<%= form_for(#organisation) do |f| %>
<% if #organisation.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#organisation.errors.count, "error") %> prohibited this organisation from being saved:</h2>
<ul>
<% #organisation.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :name %><br>
<%= f.text_field :name %>
</div>
<%= f.fields_for #address do |t| %>
<div>
<%= t.label :Line_1 %><br />
<%= t.text_field :line1 %>
</div>
<div>
<%= t.label :Line_2 %><br />
<%= t.text_field :line2 %>
</div>
<div>
<%= t.label :Line_3 %><br />
<%= t.text_field :line3 %>
</div>
<div>
<%= t.label :Line_4 %><br />
<%= t.text_field :line4 %>
</div>
<div>
<%= t.label :Postcode %><br />
<%= t.text_field :postcode %>
</div>
<div>
<%= t.label :Country %><br />
<%= t.text_field :country %>
</div>
<% end %>
<div class="field">
<%= f.label :phone %><br>
<%= f.text_field :phone %>
</div>
<div class="actions">
<%= f.submit %>
</div>
controllers/organisations_controller.rb
class OrganisationsController < ApplicationController
espond_to :html, :json
before_action :set_organisation, only: [:show, :edit, :update, :destroy]
def new
#organisation = Organisation.new
#address = Address.new
respond_with(#organisation)
end
def create
puts "Start of debug"
puts organisation_params[:address_attributes]
puts "End of debug"
#organisation = Organisation.new(organisation_params)
#address = Address.new(organisation_params[:address_attributes])
#address.save
#organisation.address = #address.id
#organisation.save
respond_with(#organisation)
end
private
def set_organisation
#organisation = Organisation.find(params[:id])
end
def organisation_params
params.require(:organisation).permit(:name, :phone, :creator, :contact, :renewal, :approved, :balance, address_attributes:[:line1, :line2, :line3, :line4, :postcode, :country, :organisation_id])
end
end
But I keep getting the following error:
Started POST "/organisations" for 127.0.0.1 at 2014-12-11 23:40:54 +0000
Processing by OrganisationsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"T2344536dhfjkhkj3eb5g43glwy547fy5p2nbydddfr=", "organisation"=>{"name"=>"The company", "address"=>{"line1"=>"1 The Road", "line2"=>"", "line3"=>"", "line4"=>"", "postcode"=>"", "country"=>"Ireland"}, "phone"=>"01111111"}, "commit"=>"Create Organisation"}
Start of debug
Unpermitted parameters: address
End of debug
Unpermitted parameters: address
Unpermitted parameters: address
(0.4ms) BEGIN
SQL (1.0ms) INSERT INTO "addresses" ("created_at", "updated_at") VALUES ($1, $2) RETURNING "id" [["created_at", "2014-12-11 23:40:54.404236"], ["updated_at", "2014-12-11 23:40:54.404236"]]
PG::NotNullViolation: ERROR: null value in column "line1" violates not-null constraint
DETAIL: Failing row contains (21, null, null, null, null, null, null, 2014-12-11 23:40:54.404236, 2014-12-11 23:40:54.404236).
: INSERT INTO "addresses" ("created_at", "updated_at") VALUES ($1, $2) RETURNING "id"
(0.4ms) ROLLBACK
Completed 500 Internal Server Error in 7ms
ActiveRecord::StatementInvalid (PG::NotNullViolation: ERROR: null value in column "line1" violates not-null constraint
DETAIL: Failing row contains (21, null, null, null, null, null, null, 2014-12-11 23:40:54.404236, 2014-12-11 23:40:54.404236).
: INSERT INTO "addresses" ("created_at", "updated_at") VALUES ($1, $2) RETURNING "id"):
app/controllers/organisations_controller.rb:29:in `create'
It looks to me that the address is not getting created because it doesn't have access to the address attributes which are passed but are 'unpermitted parameters'. Even though I include it in the organisation_params.permit statement????
Am I doing something wrong here?
Edit 1
As per hkumar's suggestion I've edited the views/organisations/_form.html.erb file to now say <%= f.fields_for "#{#address}_attributes" do |t| %>
But the error now looks like:
Parameters: {"utf8"=>"✓", "authenticity_token"=>"T2344536dhfjkhkj3eb5g43glwy547fy5p2nbydddfr=", "organisation"=>{"name"=>"The company", "#<Address:0x00000003aa2690>_attributes"=>{"line1"=>"The Road", "line2"=>"", "line3"=>"", "line4"=>"", "postcode"=>"", "country"=>"Ireland"}, "phone"=>"01111111"}, "commit"=>"Create Organisation"}
Start of debug
Unpermitted parameters: #<Address:0x00000003aa2690>_attributes
End of debug
Edit 2
Followed Paul Richter's advice and now the error is:
Started POST "/organisations" for 127.0.0.1 at 2014-12-12 01:35:13 +0000
Processing by OrganisationsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"T2344536dhfjkhkj3eb5g43glwy547fy5p2nbydddfr=", "organisation"=>{"name"=>"The company", "address_attributes"=>{"line1"=>"The road", "line2"=>"", "line3"=>"", "line4"=>"", "postcode"=>"", "country"=>"Ireland"}, "phone"=>"01111111"}, "commit"=>"Create Organisation"}
Start of debug
{"name"=>"The company", "phone"=>"01111111", "address_attributes"=>{"line1"=>"The road", "line2"=>"", "line3"=>"", "line4"=>"", "postcode"=>"", "country"=>"Ireland"}}
End of debug
(0.6ms) BEGIN
SQL (0.9ms) INSERT INTO "addresses" ("created_at", "updated_at") VALUES ($1, $2) RETURNING "id" [["created_at", "2014-12-12 01:35:14.196724"], ["updated_at", "2014-12-12 01:35:14.196724"]]
PG::NotNullViolation: ERROR: null value in column "line1" violates not-null constraint
DETAIL: Failing row contains (46, null, null, null, null, null, null, 2014-12-12 01:35:14.196724, 2014-12-12 01:35:14.196724).
: INSERT INTO "addresses" ("created_at", "updated_at") VALUES ($1, $2) RETURNING "id"
(0.3ms) ROLLBACK
Completed 500 Internal Server Error in 57ms
ActiveRecord::StatementInvalid (PG::NotNullViolation: ERROR: null value in column "line1" violates not-null constraint
DETAIL: Failing row contains (46, null, null, null, null, null, null, 2014-12-12 01:35:14.196724, 2014-12-12 01:35:14.196724).
: INSERT INTO "addresses" ("created_at", "updated_at") VALUES ($1, $2) RETURNING "id"):
app/controllers/organisations_controller.rb:29:in `create'
Final edit
Thanks to Paul Richter, the following code now works (for anyone who stumbles across it):
controllers/organisations_controller.rb
class OrganisationsController < ApplicationController
espond_to :html, :json
before_action :set_organisation, only: [:show, :edit, :update, :destroy]
def new
#organisation = Organisation.new
#organisation.build_address
end
def create
#organisation = Organisation.new(organisation_params)
#organisation.save
respond_with(#organisation)
end
private
def set_organisation
#organisation = Organisation.find(params[:id])
end
def organisation_params
params.require(:organisation).permit(:name, :phone, :creator, :contact, :renewal, :approved, :balance, address_attributes:[:line1, :line2, :line3, :line4, :postcode, :country, :organisation_id])
end
end
The issue relates to this line in the form:
f.fields_for #address do |t|
And this line in the controller (showing the full method so we are all on the same page):
def new
#organisation = Organisation.new
#address = Address.new # This line, specifically
respond_with(#organisation)
end
The problem is that you're creating separate Address and Organization objects as though they are separate independent entities, but since Address belongs_to Organization (according to your model), Address is actually dependent on the parent Organization, and therefore should be associated properly.
Instead, you would want to do this:
def new
#organisation = Organisation.new
#organization.build_address
...
This will set up a new Address object which is associated with its parent Organization.
Then in the form, change the fields_for line to this:
f.fields_for :address do |t|
This will call the address method of the #organization object, and [insert rails magic] the naming convention for accepts_nested_attributes_for will be used instead.
So in short, the reason you were seeing the error is because, while you had indeed set up the strong parameters correctly, the fact that a separate, disconnected Address object was being passed to f.fields_for prevented the form fields from being named correctly.
Edit
Now that the form is set up properly, change the create method to look like this:
def create
#organisation = Organisation.new(organisation_params)
#organisation.save
respond_with(#organisation)
end
In the comments below, you were mentioning how to get the id of the address I'm creating and store it on the organisation. To be clear, there is no id of the address at this point, but because you've set up the accepts_nested_attributes_for :address line in the Organization model, Rails will create a new Address object already associated to the Organization by using the address_attributes parameters in the organization_params hash you passed in.
This one line (Organisation.new(organisation_params)) creates the whole structure for you, so long as the parameters match the expected naming convention, which they now should.

What can prevent an attribute from being created in rails?

Everything doesn't seem to be too hard but I've spent hours yet still can't get it working.
If I do Category.create(:name => "foo") in the rails console, a new category with its name gets created beautifully.
(0.2ms) begin transaction
SQL (0.3ms) INSERT INTO "categories" ("created_at", "name", "updated_at") VALUES (?, ?, ?) [["created_at", "2014-09-16 15:40:01.218700"], ["name", "foo"], ["updated_at", "2014-09-16 15:40:01.218700"]]
(14.5ms) commit transaction
=> #<Category id: 38, created_at: "2014-09-16 15:40:01", updated_at: "2014-09-16 15:40:01", name: "foo">
However, if I do it on the pages something goes wrong. My Category model has only one attribute which is "name", and I want all of them to be listed on my category index page.
<% #categories.each do |category| %>
<ul>
<li>
<b><%= category.name %></b><br />
<% category.products.each do |product| %>
<%= product.title %><br />
<% end %>
</li>
</ul>
<% end %>
<%= link_to "Create new category", categories_new_path %>
If I create a new category with its name in the console, it appears on the page with its name with no problem. But if I create it on the page, there's a category created with its name attribute being "nil". So please help me figure out where the problem is. I'm quite new to rails.
Here's my categories_controller.erb
class CategoriesController < ApplicationController
# load_and_authorize_resource
def new
#category = Category.new
end
def create
#category = Category.new(params[:name])
if #category.save
redirect_to categories_path
else
render 'new'
end
end
def index
#categories = Category.all
end
end
And here's my new.html.erb
<h1>New Category</h1>
<%= form_for(#category) do |f| %>
<div class="field">
<%= f.label :name %><br>
<%= f.text_field :name %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
<%= link_to 'Back', categories_path %>
Here's what appears in the server after I hit the submit button.
Started POST "/categories?locale=en" for 127.0.0.1 at 2014-09-17 00:02:42 +0800
Processing by CategoriesController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"ZdXcC/uEMA/jhGoGhYvp4lSHHfi/tmlm3CovJcYizJ0=", "category"=>{"name"=>"fwefewfw"}, "commit"=>"Create Category", "locale"=>"en"}
(0.1ms) begin transaction
SQL (0.2ms) INSERT INTO "categories" ("created_at", "updated_at") VALUES (?, ?) [["created_at", "2014-09-16 16:02:42.806041"], ["updated_at", "2014-09-16 16:02:42.806041"]]
(21.2ms) commit transaction
Note that there's no "name" being inserted in the sql statement.
I sense I missed something that is very basic. Well forgive me for being a newbie and thank you for the help!!
Looking at your tags, i think you are using rails 4 so you need to permit your attributes first. You can do it by this:
class CategoriesController < ApplicationController
# load_and_authorize_resource
def create
#category = Category.new(category_params)
if #category.save
redirect_to categories_path
else
render 'new'
end
end
private
def category_params
params.require(:category).permit(:name)
end
end
For details checkout Strong Parameters in Rails
It should be:
#category = Category.new(params[:category])
If you're on Rails 4, you should use the strong params and add the following method to your controller:
def category_params
params.require(:category).permit(:name)
end
And then change the Category.new line to:
#category = Category.new(category_params)
That's the new "safe" way to accept user-generated data in Rails models, and works really well once you get used to it.

rails namespace form does not write data to database

i´m new to rails and like to know why my form does not write the data to the database?
if i show the data in the controller like
render text: params[:post].inspect
it is showing me the correct details. if i send the form to the database is showing just a new id and the created_at and updated_at data.
maybe there is someone who can help me...
here are my files:
LOG:
tarted POST "/manage/rooms" for 127.0.0.1 at 2014-03-12 09:45:28 +0100
Processing by Manage::RoomsController#create as HTML
Parameters: {"utf8"=>"✓","authenticity_token"=>"7IrPpFfkK4Krc4u6YYpUcaCp+",
"rooms"=>{"number_of_rooms"=>"1", "occupancy"=>"1", "room_type"=>"Private Room",
"gender"=>"mixed", "title"=>"foo"}, "commit"=>"Save Rooms"} (0.2ms) BEGIN
SQL (0.4ms) INSERT INTO "rooms" ("created_at", "updated_at") VALUES ($1, $2)
RETURNING "id" [["created_at", Wed, 12 Mar 2014 08:45:28 UTC +00:00],
["updated_at", Wed, 12 Mar 2014 08:45:28 UTC +00:00]] (660.8ms) COMMIT
Redirected to http://localhost:3000/manage/rooms/27
Completed 302 Found in 664ms (ActiveRecord: 661.3ms)
controller: ( controllers/manage/room_cont...)
class Manage::RoomsController < ApplicationController
def new
end
def create
#render text: params[:rooms].inspect
#room = Room.new(params[:room])
#room.save
redirect_to [:manage, #room]
end
def show
#room = Room.find(params[:id])
end
private
def room_params
params.require(:room).permit(:number_of_rooms, :occupancy, :room_type, :gender, :title)
end
end
model: (models/room.rb )
class Room < ActiveRecord::Base
end
form: ( /views/manage/rooms/form.html... )
<%= simple_form_for [:manage, #room], manage_room_path do |f| %>
<p>
<%= f.input :number_of_rooms, collection: 1..20, :include_blank => false %>
</p>
<p>
<%= f.input :occupancy, collection: 1..20, :include_blank => false %>
</p>
<p>
<%= f.input :room_type, collection: ["Private Room", "Shared Room (Dorm)"],:include_blank => false %>
</p>
<p>
<%= f.input :gender, collection: ["mixed", "male", "female"], :include_blank => false %>
</p>
<P>
<%= f.label :title %><br>
<%= f.text_field :title %>
</p>
<p>
<%= f.submit %>
</p>
<% end %>
routes:
manage_rooms GET /manage/rooms(.:format) manage/rooms#index
POST /manage/rooms(.:format) manage/rooms#create
new_manage_room GET /manage/rooms/new(.:format) manage/rooms#new
edit_manage_room GET /manage/rooms/:id/edit(.:format) manage/rooms#edit
manage_room GET /manage/rooms/:id(.:format) manage/rooms#show
PATCH /manage/rooms/:id(.:format) manage/rooms#update
PUT /manage/rooms/:id(.:format) manage/rooms#update
DELETE /manage/rooms/:id(.:format) manage/rooms#destroy
Thanks!
In your create action:
#room = Room.new(room_params)
and in your room_params method, do: params.require(:rooms).permit...

Rails 4, double-nested models and strong parameters

I am fairly new to Ruby on Rails and began with rails 4 right away.
I have sucessfully nested a Recipe and a Ingredient model so that they can be added in the same form. Next I want to nest quantity within ingredient so that that aswell can be added within the same form. Everything seems to be working fine up until when the quantity of the ingredient is about to be inserted in the database and from this i believe there is something wrong with the strong params in the recipes_controller. But i will post the full code below.
I am using simple_form for the forms.
Thankful for any help!
Here are my models:
class Recipe < ActiveRecord::Base
has_many :comments, dependent: :destroy
has_many :ingredients, dependent: :destroy
accepts_nested_attributes_for :ingredients, :reject_if => lambda { |a| a[:name].blank? }, :allow_destroy => true
validates :title, presence: true
validates :desc, presence: true
end
class Ingredient < ActiveRecord::Base
belongs_to :recipe
has_many :quantities, dependent: :destroy
accepts_nested_attributes_for :quantities, :reject_if => lambda { |a| a[:name].blank? }, :allow_destroy => true
end
class Quantity < ActiveRecord::Base
belongs_to :ingredient
end
Here is the recipes_controller
class RecipesController < ApplicationController
def new
#recipe = Recipe.new
3.times do
ingredient = #recipe.ingredients.build
1.times {ingredient.quantities.build }
end
end
def create
#recipe = Recipe.new(params[:recipe].permit(:title, :desc, ingredients_attributes: [:id, :recipe_id, :name, :_destroy, quantities_attributes: [:id, :ingredient_id, :amount, :unit, :_destroy]]))
if #recipe.save
redirect_to #recipe
else
render "new"
end
end
def show
#recipe = Recipe.find(params[:id])
end
def edit
#recipe = Recipe.find(params[:id])
end
def update
#recipe = Recipe.find(params[:id])
if #recipe.update(params[:recipe].permit(:title, :desc))
redirect_to #recipe
else
render 'edit'
end
end
def destroy
#recipe = Recipe.find(params[:id])
#recipe.destroy
redirect_to recipes_path
end
def index
#recipes = Recipe.all
end
private
def post_params
params.require(:recipe).permit(:title, :desc, ingredients_attributes: [:id, :recipe_id, :name, :_destroy, quantities_attributes: [:id, :ingredient_id, :amount, :unit, :_destroy]])
end
end
Then i use simple form to create a form for recipe, ingredient and quantity through partials.
_form:
<%= simple_form_for #recipe do |f| %>
<%= f.error_notification %>
<%= f.input :title %>
<%= f.input :desc %>
<%= f.simple_fields_for :ingredients do |builder| %>
<%= render "ingredient_fields", :f => builder %>
<% end %>
<p class="links">
<%= link_to_add_association 'add ingredient', f, :ingredients %>
<p class="links">
<%= f.error :base%>
<%= f.submit %>
<% end %>
Which renders from _ingredients_fields:
<div class="nested-fields">
<%= f.input :name, label: "Ingredient" %>
<%= f.simple_fields_for :quantities do |builder| %>
<%= render "quantities_fields", :f => builder %>
<% end %>
<%= link_to_remove_association "remove", f %>
</div>
which renders from _quantities_fields: [EDITED]
<div class="nested-fields">
<%= f.input :amount %>
<%= f.input :unit %>
</div>
Trying to add new recipes result in the following log statement:
Started POST "/recipes" for 127.0.0.1 at 2013-10-29 14:15:40 +0100
Processing by RecipesController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"t6LKgDLwAxaU9xo2ipyCM+j1yfVF9WrI8AoGTX+gRkw=", "recipe"=>{"title"=>"Pancakes", "desc"=>"Tasty", "ingredients_attributes"=>{"0"=>{"name"=>"Milk", "quantities_attributes"=>{"0"=>{"amount"=>"1", "unit"=>"Cup"}}, "_destroy"=>"false"}}}, "commit"=>"Create Recipe"}
[1m[35m (0.1ms)[0m begin transaction
[1m[36mSQL (3.5ms)[0m [1mINSERT INTO "recipes" ("created_at", "desc", "title", "updated_at") VALUES (?, ?, ?, ?)[0m [["created_at", Tue, 29 Oct 2013 13:15:40 UTC +00:00], ["desc", "Tasty"], ["title", "Pancakes"], ["updated_at", Tue, 29 Oct 2013 13:15:40 UTC +00:00]]
[1m[35mSQL (0.4ms)[0m INSERT INTO "ingredients" ("created_at", "name", "recipe_id", "updated_at") VALUES (?, ?, ?, ?) [["created_at", Tue, 29 Oct 2013 13:15:40 UTC +00:00], ["name", "Milk"], ["recipe_id", 27], ["updated_at", Tue, 29 Oct 2013 13:15:40 UTC +00:00]]
[1m[36m (7.8ms)[0m [1mcommit transaction[0m
Redirected to http://www.projectcookbook.dev/recipes/27
Completed 302 Found in 22ms (ActiveRecord: 11.7ms)
You're using similar render for _quantities and _ingredients partials, which is wrong. In _quantities_field you don't need
<%= f.simple_fields_for :quantities do |builder| %>
<%= render "quantities_fields", :f => builder %>
<% end %>
AND should adjust
<%= f.input :name, label: "Quantity" %>
in _quantities_fields.
UPD
I think the problem is in :reject_if-clause at Ingredient model. It should be
:reject_if => lambda { |a| a[:amount].blank? }
bc here you specify conditions for Quantity, not for Ingredient
On code styling:
1) In controller it's better to use relevant name of private method for strong parameters: recipe_params instead of post_params and then use it for creation of new Recipe #recipe = Recipe.new(recipe_params)
2) Current associations between Recipe, Ingredient and Quantity will lead to Ingredient duplication in case two Recipes use similar one. The reason is belongs_to, which define single association. Try another approach (bellow).
BTW. recently I've answered on the similar question. Check it out: How do I reference an existing instance of a model in a nested Rails form?
I thing you are missing in this part
<%= simple_form_for #recipe do |f| %>
it should be
<%= simple_nested_form_for #recipe do |f| %>

Resources