Rails 4 nested strong parameters throwing unpermited parameters error - ruby-on-rails

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.

Related

Ruby Rails Tagging - many to many relation with 3 tables - in middle (through) table double rows

i have this situation in Ruby on Rails (5.0)
Many tags have many conditions
In case one same condition for more tags - then must be determined concrete percentage partition
Examples
Tag "work" has condition "VS Code" percent 40
Tag "paid" has condition "VS Code" percent 60
Tag "work" has condition "Calc" percent 100
Tag "funny" has condition "Youtube" percent 100
Main table Tag
table structure---------------------
t.string :name
t.datetime :valid_from
t.datetime :valid_to
with model--------------------------
class Tag < ApplicationRecord
has_many :groupings, dependent: :destroy
has_many :groups, through: :groupings
has_many :tag_conditionings, dependent: :destroy
has_many :tag_conditions, through: :tag_conditionings
accepts_nested_attributes_for :tag_conditions
accepts_nested_attributes_for :tag_conditionings
end
Another table Tag_condition
table structure---------------------
condition:string
with model--------------------------
class TagCondition < ApplicationRecord
belongs_to :tag, optional: true
end
And between table Tag_conditioning (with percent)
table structure---------------------
t.references :tag_condition, foreign_key: true
t.references :tag, foreign_key: true
t.integer :percent
with model--------------------------
class TagConditioning < ApplicationRecord
belongs_to :tag_condition, optional: true
belongs_to :tag, optional: true
end
I have one view with 2 nested forms - if i understand right
<%= form_for(tag) do |f| %>
<div class="field">
<%= f.label :name %>
<%= f.text_field :name %>
</div>
<%= f.fields_for :**tag_conditions** do |c| %>
<div class="field">
<%= c.label :**condition** %>
<%= c.text_field :**condition** %>
</div>
<% end %>
<%= f.fields_for :**tag_conditionings** do |c| %>
<div class="field">
<%= c.label :**percent** %>
<%= c.text_field :**percent** %>
</div>
<% end %>
<div class="field">
<%= f.label :valid_from %>
<%= f.datetime_select :valid_from %>
</div>
<div class="field">
<%= f.label :valid_to %>
<%= f.datetime_select :valid_to %>
</div>
Controller - tags_controllers.rb
def new
#tag = Tag.new
#tag.tag_conditions.build
#tag.tag_conditionings.build
end
def create
#tag = Tag.new(tag_params)
respond_to do |format|
if #tag.save
format.html { redirect_to #tag, notice: 'Tag was successfully created.' }
format.json { render :show, status: :created, location: #tag }
else
format.html { render :new }
format.json { render json: #tag.errors, status: :unprocessable_entity }
end
end
end
private
def tag_params
params.require(:tag).permit(:name, :percent, :valid_from, :valid_to, tag_conditions_attributes: [:condition], tag_conditionings_attributes: [:percent])
end
Everything is ok, only in table tag_conditionings i have double INSERTS and therefore double ROWS
INSERT INTO "tags" ("name", "valid_from", "valid_to", "created_at", "updated_at") VALUES ($1, $2, $3, $4, $5) RETURNING "id" [["name", "sdf"], ["valid_from", "2020-05-08 19:56:00"], ["valid_to", "2020-05-08 19:56:00"], ["created_at", "2020-05-08 19:56:55.811745"], ["updated_at", "2020-05-08 19:56:55.811745"]]
**first INSERT**
INSERT INTO "tag_conditionings" ("tag_id", "created_at", "updated_at") VALUES ($1, $2, $3) RETURNING "id" [["tag_id", 14], ["created_at", "2020-05-08 19:56:55.843693"], ["updated_at", "2020-05-08 19:56:55.843693"]]
INSERT INTO "tag_conditions" ("condition", "created_at", "updated_at") VALUES ($1, $2, $3) RETURNING "id" [["condition", "50sd"], ["created_at", "2020-05-08 19:56:55.865495"], ["updated_at", "2020-05-08 19:56:55.865495"]]
**second INSERT**
INSERT INTO "tag_conditionings" ("tag_condition_id", "tag_id", "created_at", "updated_at") VALUES ($1, $2, $3, $4) RETURNING "id" [["tag_condition_id", 16], ["tag_id", 14], ["created_at", "2020-05-08 19:56:55.919774"], ["updated_at", "2020-05-08 19:56:55.919774"]]
I am amateur newie, can you help me? What I have wrong? I spent many hours for googling, reading, testing, but zero result.
Thank you very much
Ivanhoe
The reason you are getting two additional rows in the tag_conditionings is that rails will implicitly create rows in the join table when you have a has_many through: association:
Tag.first
.tag_conditions
.create(some_attribute: 'some_value')
The above create 1 row in tag_conditions and 1 row in tag_conditionings.
The same applies when you are using nested attributes:
Tag.create(
tag_conditions_attributes: [{ some_attribute: 'some_value' }]
)
If you want to create the join table entity explicitly and the joined entity you need to nest the nested attributes:
class TagConditioning < ApplicationRecord
belongs_to :tag_condition, optional: true
belongs_to :tag, optional: true
accepts_nested_attributes_for :tag_conditions
end
Tag.create(
tag_conditioning_attributes: [
{
percent: 50,
tag_condition_attributes: [
{ some_attribute: 'some_value' }
]
}
]
)
In the form you do this by nesting the call to fields_for:
<%= form_with(model: #tag) do |f| %>
<%= f.fields_for :tag_conditionings do |conditionings| %>
<%= conditionings.number_field :percent, in: 1..100 %>
<%= conditionings.fields_for :tag_conditions do |tc| %>
<%= tc.text_field :conditions %>
<% end %>
<% end %>
# ...
<% end %>
And you whitelist the nested-nested attributes through:
def tag_attributes
params.require(:tag)
.permit(
:foo,
:bar,
tag_conditionings_attributes: [
:percent,
tag_conditions_attributes: [
:conditions
]
]
)
end
I really would not recommend nesting deeper then this as the complexity level just gets insane. The alternative is setting up separate API endpoints and using ajax calls to update the "nested" records in a way that's seamless to the user but actually atomic.

Unpermitted parameters: author

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

How to create a new child object and then create a has_and_belongs_to_many relationship with that child object in the same form

I'm new to rails and building a relational database application.
I have a somewhat complex database structure, and am trying to create a nested form that creates a child object, and then associates that child object to existing objects through a habtm relationship.
My goal is to make entering data into this database as streamlined as possible. I used Railscast #196-197 to get this far.
Partial Database Structure:
category <-- habtm --> service <-- belongs_to --> provider
Categories have many services, services may be in many categories.
Providers have many services, services belong to a single provider.
Providers may have services in many different categories.
Models:
class Provider < ActiveRecord::Base
has_many :services, :dependent => :destroy
accepts_nested_attributes_for :services, allow_destroy: true
end
class Service < ActiveRecord::Base
belongs_to :provider
has_and_belongs_to_many :categories
has_many :comments
end
I have a nested form that allows me to add a service from the same form where I am adding a provider.
I have also generated a list of categories (check boxes) to allow the user to associate the service with categories.
The problem is that when I submit the form, the join table for services_categories is not being created.
This is the information from the console that I am getting when I submit my "Create Provider" form. I can see where the category_ids[] are being stored, but they're not being passed anywhere and they aren't initiating the creation of entries in the join table.
Console Printout:
Started POST "/providers" for ::1 at 2015-05-06 14:38:36 -0700
Processing by ProvidersController#create as HTML
Parameters: {"utf8"=>"√", "authenticity_token"=>"MJXUbLeh+pT3OSC6B2pfGnsUOBkG1
jim2GUpKD9KC72vp3trLAc4Zf+ICZ6yGLiagTGQXMsJ/j8iDpbpCBhUxQ==", "provider"=>{"name
"=>".Test Provider", "organization"=>".Test Organization", "contact"=>"", "phone
"=>"", "website"=>"", "address1"=>"", "address2"=>"", "city"=>"", "state"=>"Onli
ne", "zip"=>"", "services_attributes"=>{"0"=>{"title"=>".Test Service", "descrip
tion"=>"", "_destroy"=>"0"}}}, "category"=>{"service_ids"=>[""]}, "service"=>{"c
ategory_ids"=>["4", "37", "36"]}, "commit"=>"Create Provider"}
(0.0ms) begin transaction
SQL (2.0ms) INSERT INTO "providers" ("name", "organization", "address1", "add
ress2", "city", "state", "phone", "website", "contact", "created_at", "updated_a
t") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) [["name", ".Test Provider"], ["org
anization", ".Test Organization"], ["address1", ""], ["address2", ""], ["city",
""], ["state", "Online"], ["phone", ""], ["website", ""], ["contact", ""], ["cre
ated_at", "2015-05-06 21:38:36.715129"], ["updated_at", "2015-05-06 21:38:36.715
129"]]
SQL (0.0ms) INSERT INTO "services" ("title", "description", "provider_id", "c
reated_at", "updated_at") VALUES (?, ?, ?, ?, ?) [["title", ".Test Service"], [
"description", ""], ["provider_id", 56], ["created_at", "2015-05-06 21:38:36.731
130"], ["updated_at", "2015-05-06 21:38:36.731130"]]
(39.0ms) commit transaction
Redirected to http://localhost:3000/providers/56
Completed 302 Found in 84ms (ActiveRecord: 41.0ms)
My providers_controller.rb (With some irrelevant parts taken out):
class ProvidersController < ApplicationController
###
def new
#provider = Provider.new
#provider.services.build
#services = Service.all
#service = Service.new
end
def edit
#provider = Provider.find(params[:id])
end
def create
#provider = Provider.new(provider_params)
if #provider.save
redirect_to #provider
else
render 'new'
end
end
###
def get_all_categories
#categories = Category.find(:all, :order => 'name')
end
private
def provider_params
params.require(:provider).permit(:name, :organization, :address1, :address2, :city, :state, :zip, :phone, :website, :contact, :service_ids => [], services_attributes: [:id, :title, :description, :_destroy, :category_ids => []])
end
end
As you can see, the attribute :category_ids =>[] isn't showing up in the list of service attributes in the console.
The relevant parts of the form that I am using to submit provider data:
<%= form_for #provider do |f| %>
<%= f.fields_for :services do |builder| %>
<%= render "services_fields", :f => builder %>
<% end %>
<%= f.submit %>
The form partial for Add New Service:
<%= f.label :title, "Service Title" %><br/>
<%= f.text_field :title %> <br/>
<%= f.label :description, "Service Description" %><br/>
<%= f.text_area :description, :rows => 3 %> <br/>
<p>
<label>Associated Categories</label>
<p>
<label>Associated Categories</label>
<div>
<%= hidden_field_tag "category[service_ids][]", nil %>
<% Category.all.sort_by{|category| category.name}.each do |category| %>
<%= check_box_tag "service[category_ids][]", category.id,
#service.categories.include?(category), id: dom_id(category) %>
<%= label_tag dom_id(category), category.name %></br>
</div>
<% end %>
</p>
<%= f.check_box :_destroy %>
<%= f.label :_destroy, "Remove Service" %><br/>
I'm interested in any way that you can think of to be able to
Add Provider
Add Service
Associate Service and Category
all in one form.
I have thought about having a pop-up window to take the user to the original Add Service form, which associates Categories, but I'm new to Rails, and I don't know how difficult that would be.
I also feel like I ought to be able to do it all on one page.
I am pretty set on having a habtm relationship between Service and Categories. It works well for all other parts of the app.
Please let me know if I can post any other relevant code snippets.
Thanks!
The attribute :category_ids =>[] isn't showing up in the list of service attributes in the console because it isn't included in params["provider"]["service_attributes"], it's inside params["service"].
This means that the category_ids aren't being accessed by the create action.
If you want associate the created service and the categories without modifying your form, you can try referencing newly created service and then updating its category_ids with 'params["service"]', or just add in the category_id's into params["provider"]["service_attributes"] before creating the provider:
params["provider"]["service_attributes"]["category_ids"] = params["service"]["category_ids"]
Although this would require you to re-whitelist the permitted attributes from params.
Or you can modify your form so that the category_ids end up nested within service_attributes in the params hash.

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.

Issue saving in nested form

I followed thos steps http://railscasts.com/episodes/197-nested-model-form-part-2 and changed purchase_product "survey" and supplier_product as "question" but is not saving and also not saving nested attributes.
Here is the controller /app/controller/purchase_product_controller.rb
class PurchaseProductController < ApplicationController
def new
#purchase = PurchaseProduct.new
1.times do
supplier_product = #purchase.supplier_products.build
end
end
def create
#purchase = PurchaseProduct.new(params[:purchase])
if #purchase.save
flash[:notice] = "Successfully created purchase."
redirect_to :action=>"index"
else
render :action => 'new'
end
end
end
Here models:
class PurchaseProduct < ActiveRecord::Base
has_many :supplier_products
accepts_nested_attributes_for :supplier_products ,:allow_destroy => true
end
class SupplierProduct < ActiveRecord::Base
belongs_to :purchase_product
end
Here is my routes: /config/routes.rb
ActionController::Routing::Routes.draw do |map|
map.root :controller => "purchase_product", :action=>"index"
map.connect ':controller/:action/:id'
map.connect ':controller/:action/:id.:format'
end
Here is the view: /app/view/purchase_product/new.html.erb
<% form_for #purchase, :url => {:controller=>"purchase_product",:action=>'create'}, :html => {:id => 'new_product_form'} do |f| %>
Name: <%= f.text_field :name %>
<% f.fields_for :supplier_products do |builder| %>
<%= render "supplier_product_fields", :f => builder %>
<% end %>
<p><%= link_to_add_fields "Add Supplier Product", f, :supplier_products %></p>
<p><%= f.submit "Submit" %></p>
<% end %>
Here is the partial view: /app/view/purchase_product/_supplier_product_fields.html.erb
<div class="fields">
Type Money: <%= f.select(:type_money,([["%", 0], ["$", 1] ]) ) %>
Cost: <%= f.text_field :amount %><%= link_to_remove_fields "remove", f %>
</div>
But was not saving and got this log:
Processing PurchaseProductController#create (for 127.0.0.1 at 2014-08-06 13:48:31) [POST]
Parameters: {"purchase_product"=>{"name"=>"testing", "supplier_products_attributes"=>{"0"=>{"amount"=>"333", "type_money"=>"0", "_destroy"=>""}}}, "commit"=>"Submit"}
PurchaseProduct Columns (0.6ms) SHOW FIELDS FROM `purchase_products`
SQL (0.1ms) BEGIN
PurchaseProduct Create (0.0ms) Mysql::Error: Column 'name' cannot be null: INSERT INTO `purchase_products` (`name`, `created_at`, `updated_at`) VALUES(NULL, '2014-08-06 18:48:31', '2014-08-06 18:48:31')
SQL (0.1ms) ROLLBACK
ActiveRecord::StatementInvalid (Mysql::Error: Column 'name' cannot be null: INSERT INTO `purchase_products` (`name`, `created_at`, `updated_at`) VALUES(NULL, '2014-08-06 18:48:31', '2014-08-06 18:48:31')):
I solved the problem of saving, changing this param in the view and saved but is not saving the other attributes
Name: <%= text_field_tag "name",#name,:name=>"purchase_product[name]" %>
I got this LOG:
Processing PurchaseProductController#create (for 127.0.0.1 at 2014-08-06 14:00:04) [POST]
Parameters: {"purchase_product"=>{"name"=>"TESTING", "supplier_products_attributes"=>{"0"=>{"amount"=>"100", "type_money"=>"0", "_destroy"=>""}}}, "commit"=>"Submit"}
PurchaseProduct Columns (0.7ms) SHOW FIELDS FROM `purchase_products`
SQL (0.1ms) BEGIN
PurchaseProduct Create (0.3ms) INSERT INTO `purchase_products` (`name`, `created_at`, `updated_at`) VALUES('TESTING', '2014-08-06 19:00:04', '2014-08-06 19:00:04')
SQL (37.0ms) COMMIT
Redirected to http://localhost:3000/
Completed in 44ms (DB: 38) | 302 Found [http://localhost/purchase_product/create]
I spent a long time searching about a solution also I recreated the project several times.
Attributes from supplier products are not saving.
Please somebody can help me with this issue?
In your controller you are grabbing the purchase key from the params hash.
#purchase = PurchaseProduct.new(params[:purchase])
But the parameters you need are actually going to be in params[:purchase_product].
#purchase = PurchaseProduct.new(params[:purchase_product])
When you use the form_for helper, the key will be named after the model which the form is built around. In your case it is a PurchaseProduct, hence why they'll be in params[:purchase_product]

Resources