Back to Home

 Yield Like Pro

Apr 23, 2017

I'm currently reading Agile Web Development with Rails 5 and following steps to create simple book store web. It is basic rails app but I'm actually suprised the fact that how things the author do differently. I also enjoy every page and learn new tricks and rails' way of doing things! There are so much to learn but here are some of things that I've learned.

The task is to creating helper method hidden_div_itemsto render partial if there is a cart.

<% if @cart %> <%= hidden_div_if(@cart.line_items.empty?, id: 'cart') do %> <%= render @cart %> <% end %> <% end %> def hidden_div_if(condition, attributes = {}, &block) if condition attributes["style"] = "display:none;" end content_tag("div", attributes, &block) end

First, I haven't used content_tag before so that's something new. If you aren't familier with this, click here. Basically, it will create html tag for you. You can pass the tag as symbol ':div', or string "div". If you look at the apidock, the last arg of the content_tag is '&block'.

content_tag(name, content_or_options_with_block = nil, options = nil, escape = true, &block)

By definition, it "Returns an HTML block tag of type name surrounding the content. Add HTML attributes by passing an attributes hash to options."

Now, let's get into '&block' and 'yield' busineses.

def print_myself(arg, &block) yield(arg) end print_myself("Horay!!") do |word| puts word end ===== OR ===== print_myself("Horay!!") { |word| puts word }

Both print_myself will call the &block with arg. When you call the function, your block looks kind of funny. It looks like completely different entity from arg. BUT this is a part of attributes for the print_myself.

In the above example of hidden_div_if, it looks even weirder because it looks like we are passing 2 arguments - @cart.line_items.empty? and id: 'cart' and the hidden_div_if is also taking 2 arguments and make attributes as an empty hash by default. So here is what's going on:

  1. id: 'cart' is going to be convert as attributes[:id] => 'cart'. If you are printing attributes inside of hidden_div_if, it will say: {:id=>"cart"}
  2. attributes["style"] = "display:none;" is adding 'style' option to the attributes, which is an option of content_tag. The name 'attributes' is optional.
  3. &block - This is what is passed and execute when the function is called. Means, it will yield <%= render @cart %>. Basically, the content_tag will 'yield' the &block.