ruby-on-railsbuttoncontrolleragilehidden

Hiding button in rails (Agile Web Development with Rails book)


This is my first question so I hope I can be as specific as possible, but don't be harsh.

I'm going through Agile Web Development with Rails and am very new to programming.

I want to hide a 'Checkout' button while I am on the order/new page so that it can't do anything nasty to the users purchase.

At the moment, I don't really understand how instance variables work, since it seems like no matter where I declare my instance variable, in a view or in orderscontroller#new, it always validates to true.

This seems to be the case because when I use the instance variable in the view to hide a div ( with hidden_div_if(condition == true) ) the buttons ALWAYS get hidden!

Not only that, but when I do:

<%= hidden_div_if( @hide_checkout_button == false ) do %>
<td><%= button_to 'Empty cart', cart, :method => :delete,
                  :confirm => 'Are you sure?' %></td>
<% end %>
<%= hidden_div_if( @hide_checkout_button == true ) do %>
  <td><%= button_to "Checkout", new_order_path, :method => :get %></td>
<% end %>

BOTH buttons get hidden! How can that be!?!

In this example, I have placed the variable declaration in views\orders_form.html.erb:

<%= @hide_checkout_button = true %>
<%= form_for(@order) do |f| %>
  <% if @order.errors.any? %>
    <div id="error_explanation">
      <h2><%= pluralize(@order.errors.count, "error") %> 
        prohibited this order from being saved:</h2>

      <ul>
        <% @order.errors.full_messages.each do |msg| %>
        <li><%= msg %></li>
      <% end %>
      </ul>
    </div>
  <% end %>

  <div class="field">
    ...

Here is a discussion-forum with solutions for this problem, but they don't work for me and I don't know why: http://pragprog.com/wikis/wiki/Pt-G-2/version/35

And here is the question itself:

What happens if you click the Checkout button in the sidebar while the checkout screen is already displayed? Can you find a way to disable the button in this circumstance? (Hint: variables set in the controller are available in layouts and partials as well as in the directly rendered template.)

If you need any more information to help please ask, I'm not quite sure how much detail to provide or what information is important.

Thanks in advance :-)

def new
    @cart = current_cart
    if @cart.line_items.empty?
      redirect_to store_url, :notice => "Your cart is empty"
      return
    end

    puts 34
    @hide_checkout_button = true
    @order = Order.new
    puts 37

    respond_to do |format|
      format.html # new.html.erb
      format.json { render json: @order }
    end
  end

Started GET "/assets/logo.png" for 127.0.0.1 at 2012-11-13 20:33:40 +0000 Served asset /logo.png - 304 Not Modified (1ms) [2012-11-13 20:33:40] WARN Could not determine content-length of response body. Set content-length of the response or set Response#chunked = true * 34 37 * /orders/new

Started GET "/orders/new" for 127.0.0.1 at 2012-11-13 20:33:49 +0000 Processing by OrdersController#new as HTML ←[1m←[36mCart Load (1.0ms)←[0m ←[1mSELECT "carts".* FROM "carts" WHERE "carts "."id" = ? LIMIT 1←[0m [["id", 63]] ←[1m←[35m (1.0ms)←[0m SELECT COUNT(*) FROM "line_items" WHERE "line_items"."c art_id" = 63


Solution

  • The problem is a missing =. do <%= %> instead.

    <%= hidden_div_if( @hide_checkout_button == true ) do %>
      <td><%= button_to "Checkout", new_order_path, :method => :get %></td>
    <% end %>
    

    Also, for boolean checks you can just do if(boolean) which will evaluate the same as if you put == true/false

    <%= hidden_div_if( @hide_checkout_button) do %>
       #...
    <% end %>
    

    You want to set that variable on the method that calls the view. In this case it is the new method in OrdersController

    def new
      @hide_checkout_button = true
    end
    

    Edit:

    add this to the hidden div just to see if it helps finding the element to set the attribute to

    <%= hidden_div_if(@hide_checkout_button, id: 'cart') do %>
    

    with (in the application helper)

    def hidden_div_if(condition, attributes = {}, &block 
      if condition
        attributes["style"] = "display: none" 
      end
      content_tag("div", attributes, &block)
    end
    

    if that doesn't do it, then just do it this way

    <% if @hide_checkout_button %>
      <td><%= button_to "Checkout", new_order_path, :method => :get %></td>
    <% else %>
      <td><%= button_to 'Empty cart', cart, :method => :delete, :confirm => 'Are you sure?' %></td>
    <% end %>