Topic: Using Ruby Blocks for Custom Rails Tags

I've wanted to persuade my Ruby code to get a little bit more intimate with some HTML. Thanks to Ruby's block mechanism, this is quite trivial.

Ok, here's the problem. I had a helper method that iterated through a collection of menu items and printed them successively to the screen. The issue is that now I want to wrap certain HTML around the links it generates, however this HTML could change rather regularly.

You've seen this work if you've ever used a for loop.

    <% that.each do |this| -%>
      <p><a href="#"><%= this %></a></p>
    <% end -%>

Beautiful. Now the cool part is we can make helper method that works in a similar fashion.

First you need the helper method, which can be added to application_helper.rb, or your controller's own helper.

      def menu_links

        menus = { 'links' => 'Links',
                  'home' => 'Home',
                  'about' => 'About Me',
                  'blog' => 'Blog' }

        for menu in menus.keys
          yield(link_to(menus[menu], :controller => menu))
        end

      end


First I create a hash containing the controller name of the menu link as the key, and the link title as the value. This is just for an example to convey this concept. In my case this data comes from the database. If you haven't used blocks before the yield method can be confusing. Basically, later on we're going to pass some code into this method, and the yield call says run that code NOW! It also takes an argument of the link that I'm generating, which will make more sense in a bit.

Right now you might be saying, "well why don't you just put the for loop in the rhtml template". Well I have my reasons so BACK OFF. No seriously the links I'm generating are very dynamic and have a lot more code associated with them. Plus I can get a lot of reuse out of it. Not only that, but this can be used in a number of different applications.

So anyway, the other part of this is the rhtml.

    <% menu_links do |link| -%>
      <div class="menu"><%= link %></div>
    <% end -%>

Awesome! The link variable represents the argument that was passed to the yield call. Now we can wrap anything we want around the link, in unadulterated HTML.

Let's jazz it up a bit. What if we want to change the div class based on whether it's a link the current page? Easy Peasey.

      def menu_links

        menus = { 'links' => 'Links',
                  'home' => 'Home',
                  'about' => 'About Me',
                  'blog' => 'Blog' }

        for menu in menus.keys
          selected = (current_page? :controller => menu) ? "_selected" : ""
          yield(link_to(menus[menu], :controller => menu), selected)
        end

      end


First we check to see if the link we're generating is the current page, and if so we pass the string "_selected" to the yield call.

    <% menu_links do |link, sel| -%>
      <div class="menu<%= sel %>"><%= link %></div>
    <% end -%>

Now we pick up the new argument and append it to the CSS class name. Viola!

As I said before, there are a number of applications that this can be used for, and it's a great excuse to learn about one of Ruby's coolest features.

Orginal Article: Using Ruby Blocks for Custom Rails Tags

Re: Using Ruby Blocks for Custom Rails Tags

I can't seem to get this to work, the error is?  How does the application know when to use the application_helper.rb do I need to put a method in the menu_controller like the error below states, if so what goes inside it?

 NoMethodError in Admin/menu#index

Showing app/views/admin/menu/index.rhtml where line #10 raised:

undefined method `menu_links' for #<#<Class:0x243d34c>:0x243d324>

Extracted source (around line #10):

7: </head>
8:
9: <body>
10: <% menu_links do |link| -%>
11:     <div class="menu"><%= link %></div>
12: <% end -%>
13: </body>

Re: Using Ruby Blocks for Custom Rails Tags

Ok I fixed that, the problem was that I had it in the wrong helper, but for some reason nothing is displaying? in the the menu controller?

Re: Using Ruby Blocks for Custom Rails Tags

Thanks this helped me to solve the problem.

Re: Using Ruby Blocks for Custom Rails Tags

Thanks this helped me too to solve the problem.

Re: Using Ruby Blocks for Custom Rails Tags

is there any tutorial for this.