Using helpers inside controllers in Ruby on Rails

:: programming, rails, ruby

Rails provides some nice helper functions (numbers, dates, etc.) that are available to views, but they’re not automatically available to controllers. I found a number of ways to accomplish this on the web, but I wasn’t satisfied with any of them.

The motivation for me to do this was to use the number_to_currency() helper function in a controller, so I’ll use that for the example. This helper is in the ActionView::Helpers::NumberHelper module, which on my Ubuntu 7.04 system is located here:

/usr/lib/ruby/gems/1.8/gems/actionpack-1.13.3/lib/action_view/helpers/number_helper.rb

It may be located elsewhere on your system. If you’re running *nix (or OSX), then typing the following command should locate it: locate number_helper.rb

If you edit number_helper.rb, you’ll notice that NumberHelper is a module and number_to_currency() is an instance method, so we’ll need an instance that has included NumberHelper to be able to call the number_to_currency() method.

One way to do this would be to create a new class that includes the module, and then create an instance of that class:

1
2
3
4
5
class MyNumberHelper
  include ActionView::Helpers::NumberHelper
end
my_helper = MyNumberHelper.new
formatted_str = my_helper.number_to_currency(n)

If we had an existing object, called obj, another way to accomplish this would be via:

obj.extend(ActionView::Helpers::NumberHelper)

Since I didn’t have an appropriate object to extend the NumberHelper module, I simply created a new one:

Object.new.extend(ActionView::Helpers::NumberHelper)

If I only need to call the helper once, I could accomplish that via:

Object.new.extend(ActionView::Helpers::NumberHelper).number_to_currency(n)

However, I preferred to create a Proc object and store it for future use:

1
2
3
4
5
format_currency = lambda { |n|
  Object.new.extend(ActionView::Helpers::NumberHelper).number_to_currency(n)
}

format_currency.call(n)

UPDATE: it’s not necessary to use the lambda (as cool as they are), simply storing the result of Object.new.extend(ActionView::Helpers::NumberHelper) is sufficient. For example:

1
2
3
x = Object.new.extend(ActionView::Helpers::NumberHelper)
x.number_to_currency(7.4)
# results in "$7.40"

END UPDATE

I deliberately wanted to avoid simply including ActionView::Helpers::NumberHelper in the controller to avoid polluting the namespace and possibly expose additional public methods in the controller.