Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ruby on Rails: create records for multiple models with one form and one submit

I have a 3 models: quote, customer, and item. Each quote has one customer and one item. I would like to create a new quote, a new customer, and a new item in their respective tables when I press the submit button. I have looked at other questions and railscasts and either they don't work for my situation or I don't know how to implement them.

quote.rb

class Quote < ActiveRecord::Base
  attr_accessible :quote_number
  has_one :customer
  has_one :item
end

customer.rb

class Customer < ActiveRecord::Base
  attr_accessible :firstname, :lastname
  #unsure of what to put here
  #a customer can have multiple quotes, so would i use has_many or belongs_to?
  belongs_to :quote
end

item.rb

class Item < ActiveRecord::Base
  attr_accessible :name, :description
  #also unsure about this
  #each item can also be in multiple quotes
  belongs_to :quote

quotes_controller.rb

class QuotesController < ApplicationController
  def index
    @quote = Quote.new
    @customer = Customer.new
    @item = item.new
  end

  def create
    @quote = Quote.new(params[:quote])
    @quote.save
    @customer = Customer.new(params[:customer])
    @customer.save
    @item = Item.new(params[:item])
    @item.save
  end
end

items_controller.rb

class ItemsController < ApplicationController
  def index
  end

  def new
    @item = Item.new
  end

  def create
    @item = Item.new(params[:item])
    @item.save
  end
end

customers_controller.rb

class CustomersController < ApplicationController
  def index
  end

  def new
    @customer = Customer.new
  end

  def create
    @customer = Customer.new(params[:customer])
    @customer.save
  end
end

my form for quotes/new.html.erb

<%= form_for @quote do |f| %>
  <%= f.fields_for @customer do |builder| %>
    <%= label_tag :firstname %>
    <%= builder.text_field :firstname %>
    <%= label_tag :lastname %>
    <%= builder.text_field :lastname %>
  <% end %>
  <%= f.fields_for @item do |builder| %>
    <%= label_tag :name %>
    <%= builder.text_field :name %>
    <%= label_tag :description %>
    <%= builder.text_field :description %>
  <% end %>
  <%= label_tag :quote_number %>
  <%= f.text_field :quote_number %>
  <%= f.submit %>
<% end %>

When I try submitting that I get an error:

Can't mass-assign protected attributes: item, customer

So to try and fix it I updated the attr_accessible in quote.rb to include :item, :customer but then I get this error:

Item(#) expected, got ActiveSupport::HashWithIndifferentAccess(#)

Any help would be greatly appreciated.

like image 351
notblakeshelton Avatar asked Jun 26 '13 21:06

notblakeshelton


2 Answers

To submit a form and it's associated children you need to use accepts_nested_attributes_for

To do this, you need to declare it at the model for the controller you are going to use (in your case, it looks like the Quote Controller.

class Quote < ActiveRecord::Base
  attr_accessible :quote_number
  has_one :customer
  has_one :item
  accepts_nested_attributes_for :customers, :items
end

Also, you need to make sure you declare which attributes are accessible so you avoid other mass assignment errors.

like image 160
creativereason Avatar answered Oct 06 '22 22:10

creativereason


If you want add info for diferent models i suggest to apply nested_model_form like this reference: http://railscasts.com/episodes/196-nested-model-form-part-1?view=asciicast.

This solution is very simple and cleanest.

like image 27
enrique-carbonell Avatar answered Oct 07 '22 00:10

enrique-carbonell