tvalent2
tvalent2

Reputation: 4999

JavaScript to remove object with ajax (destroy.js.erb) not working

In my Rails 3 app I am allowing users to add awards to their profiles. Using Rails UJS I get the create working with ajax. However, I can't for the life of me get destroy to work. Looking inside my server log, it looks like it's working, but the @award isn't removed unless I refresh my profile page.

The code I used is from a tutorial I was following in Beginning Rails 3. If anyone can help me figure out what's going on wrong in my code I'd appreciate it.

My awards_controller.rb:

def create
  @award = Award.new(params[:award])
  if @award.save!
    respond_to do |format|
      #format.html { redirect_to profile_path(@profile) }
      format.js { }
    end
  else
    respond_to do |format|
      #format.html { redirect_to profile_path(@profile)}
      format.js { render 'fail_create_award.js.erb' }
    end
  end
end

def destroy
  @award = Award.find(params[:id])
  @award.destroy
  respond_to do |format|
    #format.html { redirect_to profile_path(@profile) }
    format.js { render :nothing => true }
  end
end

My create.js.erb:

$('ul#awardInfo').append("<%= escape_javascript(render(@award)) %>");
$('#new_award')[0].reset();

My destroy.js.erb:

$("ul#awardInfo<%= (@award) %>").remove();

My form to delete the award, which appears as an "x" next to the award if the award belongs to/was created by the current_user:

<li>-&nbsp;<%= award.body %><% if @profile = current_user.profile %><span class="delete"><%= link_to 'x', award_path(award), :method => :delete, :remote => true, :confirm => "Are you sure you want to remove this award?", :class => "delete_award" %></span><% end %></li>

In my server log when I click "delete" (but before refreshing the page):

Started DELETE "/awards/8" for 127.0.0.1 at 2012-01-11 21:34:58 -0500
  Processing by AwardsController#destroy as JS
  Parameters: {"id"=>"8"}
  Award Load (1.0ms)  SELECT "awards".* FROM "awards" WHERE "awards"."id" = '8' LIMIT 1
  SQL (0.2ms)  BEGIN
  SQL (1.4ms)   SELECT a.attname, format_type(a.atttypid, a.atttypmod), d.adsrc, a.attnotnull
 FROM pg_attribute a LEFT JOIN pg_attrdef d
 ON a.attrelid = d.adrelid AND a.attnum = d.adnum
 WHERE a.attrelid = '"awards"'::regclass
 AND a.attnum > 0 AND NOT a.attisdropped
 ORDER BY a.attnum

  AREL (0.6ms)  DELETE FROM "awards" WHERE "awards"."id" = 8
  SQL (2.3ms)  COMMIT
Rendered text template (0.0ms)
Completed 200 OK in 31ms (Views: 1.3ms | ActiveRecord: 5.4ms)

UPDATE: If I remove render :nothing => true from my destroy action, it doesn't actually remove the award. My log shows the following:

Started DELETE "/awards/3" for 127.0.0.1 at 2012-02-03 07:54:34 -0500
  Processing by AwardsController#destroy as JS
  Parameters: {"id"=>"3"}
  Award Load (238.1ms)  SELECT "awards".* FROM "awards" WHERE "awards"."id" = '3' LIMIT 1
  SQL (0.4ms)  BEGIN
  SQL (1.6ms)   SELECT a.attname, format_type(a.atttypid, a.atttypmod), d.adsrc, a.attnotnull
 FROM pg_attribute a LEFT JOIN pg_attrdef d
 ON a.attrelid = d.adrelid AND a.attnum = d.adnum
 WHERE a.attrelid = '"awards"'::regclass
 AND a.attnum > 0 AND NOT a.attisdropped
 ORDER BY a.attnum
  AREL (97.3ms)  DELETE FROM "awards" WHERE "awards"."id" = 3
  SQL (45.8ms)  COMMIT
Rendered awards/destroy.js.erb (1.1ms)
Completed 200 OK in 954ms (Views: 531.9ms | ActiveRecord: 383.2ms)

UPDATE 2: So a weird thing happens if I go to check the HTML:

The <li> is the actual award created. I have an award.rb model that belongs_to :profile. If the profile awards belong to my profile, I see a delete option, which is what the <span> is for.

Upvotes: 1

Views: 4682

Answers (1)

Ryan
Ryan

Reputation: 1811

Putting format.js { render :nothing => true } in your destroy action is presumably telling Rails to not render your destroy.js.erb.

Using the same format.js { } as used in the create action should direct Rails to render destroy.js.erb and subsequently execute the desired action.

Update:

From the code above, it looks like there's nothing in the actual award HTML that can be used to select on for the remove call.

I'd recommend making sure the li elements include ID attributes with the award ID in them. Something like:

<li id="award-<%= @award.id %>">

Then, to remove the award, select its li element and remove as follows:

$('li#award-<%= @award.id %>').remove();

It looks to me like the only remaining issue is that the jQuery call isn't selecting the right element, or any element at all, to call remove on. Giving the li a unique ID and then selecting that ID for removal should make the destroy action render properly.

Upvotes: 4

Related Questions