I have two separate models/controllers. One is called “Merchants” another call “CompanyLocations”. I need to be able to add a new merchant and at least one location on the same form. With button that allow me to add more locations if needed.
Using sample data I have populated the first 5 of 30 merchants with location data. And now have the Show Merchant view working fine, it shows the Merchant and the company locations underneath.
My problem is on thew new/edit pages. I cannot seem to get another location put into the DB associated with the Merchant id.
The error I am getting is : “undefined method `company_locations’ for nil:NilClass” after i try to add a company location on the merchant edit page.
As well i get an error when i try to add a new merchant. And the add button shows up twice, once for the new merchant and once for the add location.
In my models I have
merchant.rb
has_many :company_locations, :dependent => :destroy
company_location.rb
belongs_to :merchant
Here are my files:
controllers/merchant_controller.rb
def new
@merchant = Merchant.new
@company_location = @merchant.company_locations.new
end
def edit
@merchant = Merchant.find(params[:id])
@company_location = @merchant.company_locations.new
end
controllers/company_locations_controller.rb
def create
@company_location = @merchant.company_locations.build(params[:company_location])
if @company_location.save
redirect_to 'merchants/show', :flash => { :success => "Company Location Added" }
else
redirect_to 'merchants/index', :flash => { :error => "Location not saved" }
end
end
def update
end
views/merchants/new.html.erb
<h1>New merchant</h1>
<%= render 'form' %>
<%= render 'company_locations/form' %>
<%= link_to 'Cancel', merchants_path %>
views/merchants/_form.html
<%= form_for(@merchant) do |f| %>
<% if @merchant.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(@merchant.errors.count, "error") %> prohibited this merchant from being saved:</h2>
<ul>
<% @merchant.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :company_name %><br />
<%= f.text_field :company_name %>
</div>
<div class="field">
<%= f.label :fanpage_url %><br />
<%= f.text_field :fanpage_url %>
</div>
<div class="field">
<%= f.label :twitter_id %><br />
<%= f.text_field :twitter_id %>
</div>
<div class="field">
<%= f.label :website_url %><br />
<%= f.text_field :website_url %>
</div>
<div class="field">
<%= f.label :contact_email %><br />
<%= f.text_field :contact_email %>
</div>
<div class="field">
<%= f.label :active %><br />
<%= f.check_box :active %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
views/company_locations/_form.html.erb
<%= form_for @company_location do |f| %>
<%= render 'shared/error_messages', :object => f.object %>
<div class="field">
<%= f.label :address1 %><br />
<%= f.text_field :address1 %>
</div>
<div class="field">
<%= f.label :address2 %><br />
<%= f.text_field :address2 %>
</div>
<div class="field">
<%= f.label :city %><br />
<%= f.text_field :city %>
</div>
<div class="field">
<%= f.label :state %><br />
<%= f.text_field :state %>
</div>
<div class="field">
<%= f.label :zip %><br />
<%= f.text_field :zip %>
</div>
<div class="field">
<%= f.label :phone %><br />
<%= f.text_field :phone %>
</div>
<div class="field">
<%= f.label :fax %><br />
<%= f.text_field :fax %>
</div>
<div class="actions">
<%= f.submit "Add Location" %>
</div>
<% end %>
If I understand your example correctly, I think the basic problem is that you are creating two separate forms on your view for two separate models. The beauty of Rails (and most current frameworks) is the ability to use ‘nested forms’. There is a nice overview (though a bit outdated) here:
http://ryandaigle.com/articles/2009/2/1/what-s-new-in-edge-rails-nested-attributes
And you can see a great Railscast on the topic here:
http://railscasts.com/episodes/196-nested-model-form-part-1
Generally speaking, you should be able to create one form that can edit the Merchant as well as its associated CompanyLocations in one fell swoop. It might take a bit of time to wrap your head around, but it simplifies your controllers and future development a great deal. Is that helpful?