Reputation: 4999
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>- <%= 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:
<li>- test<span class="delete"><a href="/awards/4" class="delete_award" data-confirm="Are you sure you want to remove this award?" data-method="delete" data-remote="true" rel="nofollow">x</a></span></li>
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
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