Reputation: 20580
I have a form with a nested object (customer < order), and it works except that it keeps creating a new customer record.
I'd like to have it check to see if an existing customer is already present in the database (using the customer's email address to search), and if so, just attach the order to the existing record, but if not, continue creating a new customer record.
I think I have to do this by using an before_save
call in my order
model, but I don't know how to pass the form parameters (email address) in there. Is this the right approach, or is there some other way?
app/models/order.rb:
class Order < ActiveRecord::Base
belongs_to :customer
...
accepts_nested_attributes_for :customer
...
end
app/models/customer.rb:
class Customer < ActiveRecord::Base
has_many :orders
...
end
app/controllers/orders_controller.rb:
def new
@order = Order.new
@order_number = "SL-#{Time.now.to_i}"
@order.customer = Customer.new
@services_available = Service.all
end
def create
@order = Order.new params[:order]
if @order.save
flash[:notice] = 'Order was successfully created.'
redirect_to @order
else
@order_number = "SL-#{Time.now.to_i}"
render :action => "new"
end
end
app/views/order/new.html.haml:
%h1 New order
- form_for @order do |order_form|
= error_messages_for :order
%p
= order_form.label :order_number
%br
= text_field_tag '', @order_number, :disabled => true, :id => 'order_number_display'
= order_form.hidden_field :order_number, :value => @order_number
- order_form.fields_for :customer do |customer_form|
%p
= customer_form.label :first_name
%br
= customer_form.text_field :first_name
%p
= customer_form.label :last_name
%br
= customer_form.text_field :last_name
%p
= customer_form.label :phone
%br
= customer_form.text_field :phone
%p
= customer_form.label :email
%br
= customer_form.text_field :email
%p= order_form.submit 'Create Order'
= link_to 'Back', orders_path
Upvotes: 2
Views: 1725
Reputation: 1474
adding
update_only => true
to
accepts_nested_attributes_for :[model]
will not destroy the nested model each time.
Upvotes: 0
Reputation: 23450
With accepts_nested_attributes_for the attributes for the nest model are passed in the params has with the key :model(s)_attributes in your case: params[:order][:customer_attributes]
Because you have the accepts_nested_attributes_for works on the belongs_to side of a one-to-many relationship you're going to have to do some extra work. By overriding the customer_attributes attr_writter created when you call accept_nested_attributes_for.
In short this should work, or at least help you figure it out:
class Order < ActiveRecord::Base
accepts_nested_attributes_for :customer
belongs_to :customer
def customer_attributes_with_existence_check=(attributes)
self.customer = Customer.find_by_email(attributes[:email])
self.customer_attributes_without_existence_check=(attributes) if customer.nil?
end
alias_method_chain 'customer_attributes=', :existence_check
end
Upvotes: 2