views:

107

answers:

0

I'm revising this question again because I solved a majority of the issues. The current bug that I could use some help with is that when I remove an object using the technique described below, I end up with orphaned database rows that should be getting deleted. Details below.

I'm using the Ryan Bates technique from Advanced Rails recipes to dynamically add and remove elements on a multi-model form. http://media.pragprog.com/titles/fr_arr/multiple_models_one_form.pdf.

I have 3 models: users, schedules and markets.
Users
has_many :schedules
has_many :markets, :through => :schedules

Markets
has_many :schedules
has_many :users, :through => :schedules

Schedules
belongs_to :users
belongs_to :markets

Schedules has columns user_id and market_id, but also has additional columns: monday, tuesday, wednesday, thursday, friday, saturday, sunday. These are booleans.

All the editing in my app happens from the user model. On the user#edit view, I'm showing the user a dropdown for each of his existing markets and for each market, I'm rendering 7 select boxes with options 'true' and 'false' representing a boolean for each day of the week. Each market selected and its associated selected dates are saved as a "schedule" record in the schedules table. The row in that table contains a user_id, a market_id, and each selected day of the week as true. The problem is that when a user removes a market from the edit page, then that schedule row should be destroyed. But this is not happening.

Instead, when I click the "remove" link for a given schedule, and I hit update, the user_id and market_id are properly deleted from the schedules table. However, the record itself is not deleting and the boolean fields representing the days of the week remain as well.

The following is my setup. You'll see that I'm following Ryan's tutorial very closely.

User#Edit view:

<%= error_messages_for :user %>
  <% form_for @user do |f| %>
    <%= add_schedule_link "+ Add another market" %>
    <div id="schedules">
      <%= render :partial => 'schedule', :collection => @user.schedules %>
  </div>
   <%= f.submit 'Update My Profile' %>
 <% end %>

User#_schedule.html.erb

<div class="schedule">
   <% new_or_existing = schedule.new_record? ? 'new' : 'existing' %>
   <% prefix = "user[#{new_or_existing}_schedule_attributes][]" %>

   <% fields_for prefix, schedule do |schedule_form| -%>
     <%= error_messages_for :schedule, :object => schedule %>
       <p><%= schedule_form.collection_select :market_id, Market.all, :id, :name, {:prompt => true} %></p>
       <p><%= link_to_function "- Remove Market", "$(this).up('.schedule').remove()" %></p>
<%= schedule_form.select :monday, [['No', false], ['Yes', true]] %>
<%= schedule_form.select :tuesday, [['No', false], ['Yes', true]] %>
<%= schedule_form.select :wednesday, [['No', false], ['Yes', true]] %>
<%= schedule_form.select :thursday, [['No', false], ['Yes', true]] %>
<%= schedule_form.select :friday, [['No', false], ['Yes', true]] %>
<%= schedule_form.select :saturday, [['No', false], ['Yes', true]] %>
<%= schedule_form.select :sunday, [['No', false], ['Yes', true]] %>
    <% end -%>
</div>

User Model:

validates_associated :schedules, :on => :update
after_update :save_schedules

  accepts_nested_attributes_for :schedules, :allow_destroy => :true,  
      :reject_if => :all_blank

  def new_schedule_attributes=(schedule_attributes)
    schedule_attributes.each do |attributes|
      schedules.build(attributes)
    end
  end

  def existing_schedule_attributes=(schedule_attributes)
    schedules.reject(&:new_record?).each do |schedule|
      attributes = schedule_attributes[schedule.id.to_s]
      if attributes
        schedule.attributes = attributes
      else
        schedules.delete(schedule)
      end
    end
  end

  def save_schedules
    schedules.each do |schedule|
      schedule.save(false)
    end
  end

User Controller

def new
  @user = User.new
end

def create
  cookies.delete :auth_token
  @user = User.new(params[:user])
  @user.save!
  flash[:notice] = "Thanks for signing up! Please check your email to activate your account before logging in."
  redirect_to login_path
rescue ActiveRecord::RecordInvalid
  flash[:error] = "There was a problem creating your account."
  render :action => 'new'
end

def edit
  @user = current_user
end

def update
  params[:user][:existing_schedule_attributes] ||= {}
  params[:user][:existing_season_attributes] ||= {}

  @user = User.find(current_user)
    if @user.update_attributes(params[:user])
      flash[:notice] = "Your information has been updated."
      redirect_to :action => 'show', :id => current_user
    else
      render :action => 'edit'
    end
end

Helpers: users_helper.rb

module UsersHelper
 def add_schedule_link(name)
    link_to_function name do |page|
    page.insert_html :bottom, :schedules, :partial => 'schedule', :object => Schedule.new
  end
end

end