The Beginner's Guide to Rails Helpers
What is a helper?
Basically helpers in Rails are used to extract complex logic out of the view so that you can organize your code better. I’ve seen two benefits for using helpers in my experience so far:
- Extract some complexity out of the view
- Make view logic easier to test
Let me explain each one of those points.
Move complexity out of the view
The first case, where you’d want to extract out the logic from the view refers mostly to cases like conditionals or calculations (these two come to mind right now). So for example where you would have something like this in the view:
<% if @user && @user.email.present? %> <%= @user.email %> <% end %>
You can clean it up a little bit and put it into a helper.
module SiteHelper def user_email(user) user.email if user && user.email.present? end end
And then in the view code, you call the helper method and pass it the user as an argument.
<%= user_email(@user) %>
This extraction makes the view code easier to read especially if you choose your helper method names wisely.
I will strongly advice against putting too much logic in the view or the helpers, try to keep them as lean as possible. You can think of the helpers as small utility functions.
If you have too much logic in the view you should think about putting it in some other place, maybe the controller or in the
The second benefit listed above for using helpers is the fact that you can isolate the view logic and test it as a unit, I personally find this one very attractive. By using a helper as opposed to dumping everything in the view, you can isolate pieces that make up the view and test each one separately (edge cases and all).
Let’s see how you would test the simple method above.
require 'rails_helper' RSpec.describe SiteHelper, :type => :helper do describe "#user_email" do context "when the user exists and has an email" do it "returns the user's email" do user = double("user", :email => "foo") expect(helper.user_email(user)).to eq("foo") end end context "when the user exists and has no email" do it "returns nil" do user = double("user", :email => nil) expect(helper.user_email(user)).to eq(nil) end end context "when the user doesn't exist" do it "returns nil" do expect(helper.user_email(nil)).to eq(nil) end end end end
That’s really nice. You’ll find the use of helpers really useful if you have a ton of view setup code like instance variables and such that you’d have to setup if you were to test the view instead.
Helpers in Rails are modules
You probably already know this but the first time I realised it was like a wakeup call. I didn’t realise that I could treat a helper just like any other ruby module. The only exception is that Rails does some magic to auto include helpers in your views. So basically you define a helper module (or let Rails generators define it for you) which will be auto-magically included in the controller and available to both the controller and the view.
The way Rails makes the helpers available for use inside the views feels almost like using global functions. You just declare a method in a helper and it’s available to use in the view without an explicit receiver. Be warned though that the
ApplicationHelper should be avoided as much as possible as it tends to become a dumping ground for code that doesn’t seem to belong anywhere in particular.
In older versions of Rails (< 4) helpers that had the same name with the controllers were only available in their corresponding controller and views, for example the helpers in
BooksHelper were available in
/views/books/*. This is no longer true in Rails 4 (thank you Dan Smith for pointing this out), each controller will include all helpers. If you prefer the old behavior you can still get to it by setting
config.action_controller.include_all_helpers = false.
What I would strongly suggest is to avoid overriding default Rails helpers like
asset_path in your own helpers as that tends to confuse other developers (or a future you) looking at the code and trying to find the route that defines that helper, I’ve been there and it ain’t pretty.
Another thing to avoid as much as possible is creating multiple helper methods with the same name even if they have their own isolated helper module and they work fine, it’s another popular source of confusion.
One thing to keep in mind is that helpers are modules and do not allow inheritance. So if you want to combine methods from other helper modules, you’d have to include those modules in your own helper module.
Helpers and arguments
I’ve seen this over and over again. Helpers relying on instance variables. Now, I’m not saying that it doesn’t work cause it does. If the view has the instance variable defined, the helper being mixed into the view context can use it. But it’s bad practice so don’t do it.
Just treat helper methods like you do any other methods and pass them arguments. Don’t rely on instance variables because you won’t be able to reuse those helpers and it will make the helper very hard to read, test and maintain. The fact that Rails mixes everything in one giant view context is not something particularly helpful in this case so try to keep instance variables away from helper methods.
Can helpers receive block arguments?
Of course they can. Blocks can be passed into any method in ruby and helper methods make no exception. I’m sure you’ve already used them but probably didn’t realise it. The most common one is got to be the form_for helper which takes a block and generates a html form with the data and fields you provide.
You can even store the block in a variable. So if you need to wrap the output of the block into some html tags for example, you can use the capture method to store the block output into a local variable that you can later use however you like.
Helpers and design patterns
There’s been a lot said about different ways of OOP-ing Rails helpers. Almost every other blog post you read about helpers mentions something about theses OOP design patterns that you could use to improve the way helpers work in Rails.
While I do see some value in these patterns, I have yet to find one that’s as easy to use and feels like less work. I think that if you keep the complexity to a minimum inside your views and your helpers you’re gonna be just fine.
If you do however find the need to use a pattern, my choice goes towards the custom Decorator pattern that you can build yourself by using the simple SimpleDelegator class from the ruby standard library.
Using helpers (example)
It’s about time to see an example that you can copy and paste in your own Rails app. So let’s look at one of the most common helper method that I use in my own apps. It provides a consistent page title for every one of my pages and also a way to override the default with a custom title.
So let’s say I want to have all my pages say
Mix & Go in their page title but for some I’d like to provide a custom title to be prepended to it, like this:
Homepage | Mix & Go.
module ApplicationHelper def page_title(title) title += " | " if title.present? title += "Mix & Go" end end
So there you have it, a simple guide to how and when to use Rails helpers to clean up your views. I’ve purposely left out all the philosophical discussions about the OOP alternatives since I don’t think they provide much value to most of the apps you’re going to build.
Share this article if you’ve learned something new about how Rails helpers work.