helper :all. What’s the point of nicely divided helper modules if they’re all injected into same namespace, overwriting each other at random? I like to write reusable helpers that individual controllers can use by implementing their version of a
foo method. I see no reason why two completely unrelated helper modules couldn’t both has a
helper :all prevents both of these and creates situations where you can accidentally overwrite a helper method in a completely different part of your application.
Obviously not everyone agrees with me because Rails continues to move in the other direction. Once upon a time, a bare controller only pulled in its default helper (ie
Bar::FooHelper) and the helpers for its ancestors. Later, the default application skeleton added
helper :all to
ApplicationController but this was still an opt in scheme. With Rails 3 it is an opt out scheme: you have to put
clear_helpers in a controller to clear out the helpers Rails includes automatically for it.
As of Rails 3.1, you can do
config.action_controller.include_all_helpers = false to escape this madness.
Rspec tries to do the right thing – if you poke into
view_example_group.rb in rspec-rails you can see it determining the default helper class and including that and
ApplicationHelper into the view object. Unforunately it also includes
controller._helpers. This controller isn’t an instance of the controller class that will use the view – it’s an instance of
ActionView::TestCase::TestController, so has Rails’ default of the full set of helpers, irrespective of how the controller in the app is configured.
The first step is of course calling
ActionView::TestCase::TestController but if your application has helper modules that are used by multiple controllers then some of your view specs may start to fail. You could of course add those helpers to the view from your
before(:each) blocks but that is a slightly nasty piece of duplication: you’ve already specified once which helpers should be used. More dangerously you could develop a situation where your view specs pass because they specify one set of helpers but your app fails because your controllers specify a different set.
To remedy this I’ve got the following in one of my apps:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
This works out what controller class the view will normally be used with, for admin/foo/bar.html.haml this would be
Admin::FooController and uses the helpers that controller would use normally.
A call to
config.include(ViewHelpersSpecHelper) in my
RSpec.configure block ensures that this module gets included everywhere relevant.
This starts to break down for partials that are rendered by multiple different controllers or for shared ones that don’t have a natural controller they can be tested with. This is perhaps the one thing that
helper :all doesn’t make worse, since it does mean that a given view is always rendered with the same set of helper functions available. If you do have such units of view and helper code, the cells library is well worth a look.