Helpers (“view helpers”) are modules where you can write methods which are automatically usable in the associated view. What’s the associated view? If your view is, say, app/views/user/prefs.rhtml, then the helper you’re after is UserHelper, found in app/helpers/user_helper.rb.
The purpose of writing a method in a helper is to simplify the view. It’s best if the view file (RHTML/RXML) is short and sweet, so you can see the structure of the output. Nitty-gritty details are best left to helper methods and partials, where they can be parametized and used repeatedly.
Note Remember that helpers can’t be used in the controller! If you need a method both in a view and a controller, define them in the controller and export them
via helper_method() .
Q: Can helpers be used in models ?
For example, in the view (views/user/books.rhtml):
You have <%= @books.size %> books in your collection:
<ul>
<%= book_list @books, :max => 5 %>
</ul>
In the helper (helpers/user_helper.rb):
def book_list(books, options={:max => 10})
max = options[:max]
list = books[0...max].map { |book|
link = link_to "#{book.title}", :action => 'book', :id => book.id
"<li>#{link}</li>"
}
# Add a "more..." link if the list is at maximum size.
if list.size == max
more_link = link_to "more...", :action => 'books_all'
list[-1] = "<li>#{more_link}</li>"
end
return list # this one was missing here AFAIK
end
And the result:
You have 2 books in your collection: * Stone Alone * Catch-22
or…
You have 37 books in your collection: * Catcher in the Rye * Fool's Gold * VB.NET Unleashed! * Harry the Houndog * more...
And there you have it. Ensuring the list only displays so many items, and making the last item a special link, is not trivial work, and that logic would clutter the view considerably. Helpers are just the tonic for such a situation.
If the view logic you want to capture in a helper is more HTML-heavy, you can use a partial instead.
Final note: each view, as stated above, has one helper module automatically wired up to it. If you are creating so many helper methods that you wish you could separate them somehow, you can:
class UserController < ApplicationController
helper :user # This is implied; you don't have to write this.
helper :extra_user
end
Your user view can now draw on the methods of two helper modules, and you can add more if you like. They share the same namespace, though, so don’t define the same method in both.
The additional helper we specified in the above controller is ExtraUserHelper, defined in app/helpers/extra_user_helper.rb.
Comment: Interesting. I would never have guessed that the name “helper” was meant to refer to views, rather than code in general. What was the rationale for putting the helper directory at the same elvel as controllers and models, rather than inside the view directory where its purpose would be more readily clear?
tag and content_tag to avoid hard coding HTMLYou are recommended to use the tag and content_tag helpers in helpers instead of plain html emitting:
with hardcoded-html
def collapsible_fieldset(options = {}, &block)
html = '<fieldset>'
html << capture(&block) if block_given?
html << '</fieldset>'
Binding.of_caller do |binding|
concat(html, binding)
end
end
using content_tag
def collapsible_fieldset(options = {}, &block)
html = content_tag :fieldset, (capture(&block) if block_given?)
Binding.of_caller do |binding|
concat(html, binding)
end
end
Be aware that you will get the view output duplicated if you call the concat method in a helper which is called from <%= %> tags. In the above example you should remove the equals sign and allow concat to output the view.
Note that in ruby 1.8.5 binding_of_caller does not work. You may use the block’s caller instead:
def collapsible_fieldset(options = {}, &block)
return unless block_given?
html = content_tag :fieldset, capture(&block)
concat( html, block.binding)
end
See also: Old dead (link removed) is partially available at http://www.planetrubyonrails.org/show/feed/164
Category: Howto