Task D: A Dash Of Ajax #1

Dave says:

First replace the button in _cart.rhtml with

<% form_remote_tag :url => { :action => :empty_cart } do %>
  <%= submit_tag "Empty cart" %>
<% end %>

Change the empty_cart method in store_controller.rb to look like:

def empty_cart
  session[:cart] = nil
  redirect_to_index unless request.xhr?
end

Notice the check to see whether or not this is an xhr request. This ensures we won't break when javscript is disabled.

Finally create empty_cart.rjs:

  page[:cart].visual_effect :blind_up

No if statement needed in this case since we there won't be any items left in the cart after this operation finishes. Additionally, we don't need to replace any html because we are just going to be rolling the div up.

Nathan Manzi says:

I chose to replace the button_to with the following:

<% form_remote_tag :url => { :action => :empty_cart }, :complete => visual_effect(:blind_up, "cart") do %>
  <%= submit_tag "Empty cart" %>
<% end %>

And leave empty_cart as-is without a request.xhr? condition. This works and saves making a seperate rjs for a single action (Am I wrong in doing this?).

Eivind says:

While this works, it creates a bug in the future. When the user enters the 'Checkout' screen, and hits the 'Empty Cart' button, the cart is emptied but the user is NOT brought back to the catalog (redirect_to_index) as one would expect.

Lon says:

I couldn't get this to work. I get an error message that I have a nil object on line #2 of _cart.rhtml.

<% unless cart.items.empty? %>

  • Lon: that line was supposed to be removed before adding the blind_down effect. Re-read the beginning of 9.4.

I tried the additional following changes with the idea of just clearing the cart rather then deleting it:

in store_controller.rb:

def empty_cart
  @cart.empty
  redirect_to_index unless request.xhr?
end

and in cart.rb:
def empty
  @items.clear
end

But still got a nil object error in store_controller.rb on the empty_cart method.

Kurt says:

I had the same problem. Notice that in the add_to_cart method in store_controller.rb you have:

@cart = find_cart

I added this line to the empty_cart method just before the redirect and it works fine now.

k9d says:

Be sure to create a new .rjs file for the empty_cart action! I was stuck for a while trying to get the :blind_up to work in the add_to_cart.rjs

Sebastien says:

It works perfectly but only if I restart the server. As it is said page 121 in 2nd Edition.

However from a semantic point of view I don't like view pages with partial HTML such as the one in /app/views/layout/store.rhtml

   <%= hidden_div_if ... %>
     some rendering stuff
   </div>

so I did add an additional parameter into the hidden_div_if method to support inner content to be handled by the helper, leaving the view structured. Here is my helper method:

   def hidden_div_if(condition, content, attributes = {} )
     if condition
       attributes["style"] = "display: none"
     end
     attrs = tag_options(attributes.stringify_keys)
     "<div #{attrs}>#{content}</div>"
   end

and the helper call looks like:
<%= hidden_div_if(@cart.items.empty?, render(:partial => "cart", :object => @cart), :id => "cart" ) %>

As I am a newbie in the rails world, maybe something similar already exists. Or there are best practice to do that. So if one of you knows a better way please post it.

theman10 says:

I thought I did everything right to get the roll-up working, but it didn't work for me. The problem: I was apparently a bit overzealous and added this line to empty_cart.rjs:

   page.replace_html("cart", :partial => "cart", :object => @cart)

I included that line because I associated the roll effect with AJAX, but indeed it's not. Leaving the page.replace line in the rjs causes nothing to happen when the Empty cart button is clicked. But you do get a lovely error in the development.log file — I get the error that Lon describes above. I'm speculating the html replacement functionality of AJAX is kicking in so it's calling the partial template to re-render and since @cart is nil, things start breaking everywhere. I tried to prevent the partial from getting called by adding an IF before the partial is called from the store.rhtml (in layouts), but it is IMPOSSIBLE to prevent because Rails is too smart and just targeting that specific partial. The only way to fix it without removing the page.replace line in empty_cart.rjs (which is extremely hacky and I didn't do it, but it should work) is making everything robust to cart being nil.

masch says:

I couldn't get this to work. When i press the empty cart button with remote_tag nothing happen. It's cleared the cart model, but it doesn't refresh the cart page.
If I use the code button, and not the remote_tag, empty_cart.rjs code is called, but not if I use the remote code.
Does anyone know what i am doing wrong?

tbrown says:

I followed Dave's instructions (first on this page), but I had to change one thing.

Instead of this:

redirect_to_index unless request.xhr?

I used:

if request.xhr?
  respond_to {|format| format.js}
else
  redirect_to_index
end

dpaschich says:

I ran into the null cart problem as well - and decided that the problem is in the model. The empty_cart
action of the store shouldn't delete the cart from the session, it should tell the cart to empty itself.

I added this method to app/models/cart.rb:

  def empty
    @items = []
  end

And then my empty_cart method in storecontroller.rb is:

  def empty_cart
    @cart = find_cart
    @cart.empty
    redirect_to_index unless request.xhr?
  end

Ujjwal Trivedi says:

I tried inserting a partial (basically a feed) in a div, but it does not respect the div style. While the html text inside the div was hidden, the partial was rendered and displayed whatever the case be.

Zach says:

As an alternative to tbrown's solution, you can do this (as we did with add_to_cart):

respond_to do |format|
  format.js if request.xhr?
  format.html { redirect_to_index }
end
Marco Rodrigues says:

I sure to prefer to use an Rails Array function to clear the items. In dpaschich method empty, how about to use:

@items.clear

instead of

@items = []
Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License