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.