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.
Code : ruby - fold - unfold
Beautiful. Now the cool part is we can make helper method that works in a similar fashion.- <% that.each do |this| -%>
- <p><a href="#"><%= this %></a></p>
- <% end -%>
First you need the helper method, which can be added to application_helper.rb, or your controller's own helper.
Code : ruby - fold - unfold
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.- 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
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.
Code : ruby - fold - unfold
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.- <% menu_links do |link| -%>
- <div class="menu"><%= link %></div>
- <% end -%>
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.
Code : ruby - fold - unfold
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.- 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
Code : ruby - fold - unfold
Now we pick up the new argument and append it to the CSS class name. Viola!- <% menu_links do |link, sel| -%>
- <div class="menu<%= sel %>"><%= link %></div>
- <% end -%>
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.
discuss this topic to forum
