HABTM join table not being updated

I've been working with the Advanced Railes Recipies PDF tutorial but seem to have hit a snag. When adding a HABTM element, locations in place of tasks in my usage, the location (address) is added to the locations table; however, the join is not added to my locations_profiles table (profile_id,location_id). Would I need to do something more than just @profile.save in the profiles controller for this to be saved properly?

I will post code when I get home but it is essentially the same as the tutorial (which doesn't mention HABTM associations unfortunetally).

As I stated before, the location is added to the locations table and the profile is added to the profiles table (if new). The problem is that the join table is not updated to match the association.

Here is my profiles controller:

  # GET /profiles/new   def new     @devices = Device.find(:all)     @profile = Profile.new     @profile.websites.build # creates first website fieldset     @profile.numbers.build # creates first number fieldset     @profile.emails.build # creates first email fieldset     @profile.locations.build # creates first location fieldset     @profile.notes.build # creates first note fieldset   end

  # GET /profiles/1/edit   def edit     @profile = Profile.find(params[:id])   end

  # POST /profiles   def create     @profile = Profile.new(params[:profile])

    if @profile.save       flash[:notice] = "Successfully created profile!"       redirect_to profile_path(@profile)     else       render :action => 'new'     end   end

  # PUT /profiles/1   def update     params[:profile][:existing_email_attributes] ||= {}     params[:profile][:existing_website_attributes] ||= {}     params[:profile][:existing_location_attributes] ||= {}     params[:profile][:existing_number_attributes] ||= {}     params[:profile][:existing_note_attributes] ||= {}

    @profile = Profile.find(params[:id])

    if @profile.update_attributes(params[:profile])       flash[:notice] = "Successfully updated profile!"       redirect_to profile_path(@profile)     else       render :action => 'edit'     end   end

profile.rb

class Profile < ActiveRecord::Base

  after_update :save_numbers   after_update :save_emails   after_update :save_locations   after_update :save_websites   after_update :save_notes

  belongs_to :user   belongs_to :type   has_many :numbers,            :dependent => :delete_all   has_many :emails,            :dependent => :delete_all   has_many :websites,            :dependent => :delete_all   has_many :notes,            :dependent => :delete_all    has_and_belongs_to_many :locations

  # Emails   def new_email_attributes=(email_attributes)     email_attributes.each do |attributes|       emails.build(attributes)     end   end   def existing_email_attributes=(email_attributes)     emails.reject(&:new_record?).each do |email|       attributes = email_attributes[email.id.to_s]       if attributes         email.attributes = attributes       else         emails.delete(email)       end     end   end   def save_emails     emails.each do |email|       email.save(false)     end   end

  # Numbers   def new_number_attributes=(number_attributes)     number_attributes.each do |attributes|       numbers.build(attributes)     end   end   def existing_number_attributes=(number_attributes)     numbers.reject(&:new_record?).each do |number|       attributes = number_attributes[number.id.to_s]       if attributes         number.attributes = attributes       else         numbers.delete(number)       end     end   end   def save_numbers     numbers.each do |number|       number.save(false)     end   end

  # Websites   def new_website_attributes=(website_attributes)     website_attributes.each do |attributes|       websites.build(attributes)     end   end   def existing_website_attributes=(website_attributes)     websites.reject(&:new_record?).each do |website|       attributes = website_attributes[website.id.to_s]       if attributes         website.attributes = attributes       else         websites.delete(website)       end     end   end   def save_websites     websites.each do |website|       website.save(false)     end   end

  # Locations   def new_location_attributes=(location_attributes)     location_attributes.each do |attributes|       locations.build(attributes)     end   end   def existing_location_attributes=(location_attributes)     locations.reject(&:new_record?).each do |location|       attributes = location_attributes[location.id.to_s]       if attributes         location.attributes = attributes       else         locations.delete(location)       end     end   end   def save_locations     locations.each do |location|       location.save(false)     end   end

  # Notes   def new_note_attributes=(note_attributes)     note_attributes.each do |attributes|       notes.build(attributes)     end   end   def existing_note_attributes=(note_attributes)     notes.reject(&:new_record?).each do |note|       attributes = note_attributes[note.id.to_s]       if attributes         note.attributes = attributes       else         notes.delete(note)       end     end   end   def save_notes     notes.each do |note|       note.save(false)     end   end

end

location.rb class Location < ActiveRecord::Base

  belongs_to :state   has_and_belongs_to_many :profiles

   validates_presence_of :address_line_1,                          :message => "If you do not wish to add this location, please click remove."    validates_presence_of :city,                          :message => "If you do not wish to add this location, please click remove."    validates_presence_of :state_id,                          :message => "If you do not wish to add this location, please click remove."   validates_numericality_of :zip,                             :allow_nil => false,                             :message => "Please enter a zip code consisting of numbers only" end

_location.html.erb <div class="location">   <% new_or_existing = location.new_record? ? 'new' : 'existing' %>   <% prefix = "profile[#{new_or_existing}_location_attributes]" %>   <% fields_for prefix, location do |location_form| -%>   <p>     Address Line 1: <%= location_form.text_field :address_line_1 %><br /

    Address Line 2: <%= location_form.text_field :address_line_2 %><br /

    City: <%= location_form.text_field :city %><br />     State: <%= location_form.select :state_id, State.find(:all).collect {|p| [ p.name, p.id ] }, { :prompt => "Select a state" } %>     Zip Code: <%= location_form.text_field :zip %><br />     Description: <%= location_form.text_field :description %><br />     <%= link_to_function "remove" , "$(this).up('.location').remove()" %>   </p>   <% end -%> </div>

_form.html.erb <%= f.hidden_field :id %> <p>First name: <%= f.text_field :first_name %></p> <p>Last name: <%= f.text_field :last_name %></p> <p>Title: <%= f.text_field :title %></p> <p>Company: <%= f.text_field :company %></p> <p>User: <%= f.text_field :user_id %></p> <p>Type: <%= f.text_field :type_id %></p>

<h2>Websites</h2> <div id="websites">   <%= render :partial => 'website', :collection => @profile.websites %> </div> <%= add_website_link "Add a Website" %>

<h2>Numbers</h2> <div id="numbers">   <%= render :partial => 'number', :collection => @profile.numbers %> </div> <%= add_number_link "Add a Number" %>

<h2>Emails</h2> <div id="emails">   <%= render :partial => 'email', :collection => @profile.emails %> </div> <%= add_email_link "Add an Email" %>

<h2>Locations</h2> <div id="locations">   <%= render :partial => 'location', :collection => @profile.locations %> </div> <%= add_location_link "Add a Location" %>

<h2>Notes</h2> <div id="notes">   <%= render :partial => 'note', :collection => @profile.notes %> </div> <%= add_note_link "Add a Note" %>

profile helper module ProfilesHelper

  def add_website_link(name)     link_to_function name do |page|       page.insert_html :bottom, :websites, :partial => 'website' , :object => Website.new     end   end

  def add_number_link(name)     link_to_function name do |page|       page.insert_html :bottom, :numbers, :partial => 'number' , :object => Number.new     end   end

  def add_email_link(name)     link_to_function name do |page|       page.insert_html :bottom, :emails, :partial => 'email' , :object => Email.new     end   end

  def add_location_link(name)     link_to_function name do |page|       page.insert_html :bottom, :locations, :partial => 'location' , :object => Location.new     end   end

  def add_note_link(name)     link_to_function name do |page|       page.insert_html :bottom, :notes, :partial => 'note' , :object => Note.new     end   end

end