Reputation: 159
I'm new to rails and I'm creating a simple app that has clients with addersses. After getting some advice and views from the stack overflow community, I decided to save addresses as a seperate model
I am now trying to implement this in my app but I'm having problems getting the address to save correctly from the "new client" form. here is my code so far:
class Address < ActiveRecord::Base
belongs_to :client
end
class Client < ActiveRecord::Base
has_one :address
before_create :build_address, unless: Proc.new { |client| client.address }
end
<%= form_for(@client) do |f| %>
<% if @client.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(@client.errors.count, "error") %> prohibited this client from being saved:</h2>
<ul>
<% @client.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>
<div class="field">
<%= f.label :phone_number %><br>
<%= f.text_field :phone_number %>
</div>
<%= f.fields_for :address do |a| %>
<div class="field">
<%= a.label :house_number %><br>
<%= a.number_field :house_number %>
</div>
<div class="field">
<%= a.label :house_name %><br>
<%= a.text_field :house_name %>
</div>
<div class="field">
<%= a.label :post_code %><br>
<%= a.text_field :post_code %>
</div>
<% end %>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
With this, the client is created successfully but the address record is created with empty fields. No errors.
Any help would be most appreciated.
Thanks
Upvotes: 1
Views: 243
Reputation: 102249
First off - there are very few situations where ActiveModel callbacks don't cause grief. Usually putting logic into your models is a good thing - but getting callbacks to run just when you need them and not for example in unrelated tests is near impossible.
In this case you only need to build the address so that the form inputs are pre populated in your new action. There is no other reason for all your Client instances to have an empty address record piggybacking on them all the time.
So instead we would do it like this:
class Client < ActiveRecord::Base
has_one :address
accepts_nested_attributes_for :address
end
class ClientController < ApplicationController
def new
@client = Client.new
@client.build_address
end
def create
@client = Client.create(client_params)
# ...
end
def client_params
params.require(:client)
.permit(
:name, :phone_number,
address_attributes: [:house_number, :house_name]
)
end
end
Upvotes: 3
Reputation: 76784
You'll need accepts_nested_attributes_for
:
#app/models/client.rb
class Client < ActiveRecord::Base
has_one :address
accepts_nested_attributes_for :address
before_create :build_address, unless: Proc.new { |client| client.address }
end
This will allow you to do the following:
#app/controllers/clients_controller.rb
class ClientsController < ApplicationController
def new
@client = Client.new
@client.build_address
end
end
This should work for you.
Upvotes: 2