75

I'm getting a NoMethodError when trying to access a method defined in one of my helper modules from one of my controller classes. My Rails application uses the helper class method with the :all symbol as shown below:

class ApplicationController < ActionController::Base
  helper :all
  .
  .
end

My understanding is that this should make all of my controller classes automatically include all of the helper modules within the app/helpers directory, therefore mixing in all of the methods into the controllers. Is this correct?

If I explicitly include the helper module within the controller then everything works correctly.

John Topley
  • 113,588
  • 46
  • 195
  • 237

14 Answers14

133

To use the helper methods already included in the template engine:

  • Rails 2: use the @template variable.
  • Rails 3: has the nice controller method view_context

Example usage of calling 'number_to_currency' in a controller method:

# rails 3 sample
def controller_action
  @price = view_context.number_to_currency( 42.0 ) 
end

# rails 2 sample
def controller_action
  @price = @template.number_to_currency( 42.0 ) 
end
gamecreature
  • 3,232
  • 3
  • 20
  • 18
51

helper :all makes all the helpers (yes, all of them) available in the views, it does not include them into the controller.

If you wish to share some code between helper and controller, which is not very desirable because helper is UI code and controller is, well, controller code, you can either include the helper in the controller, or create a separate module and include that in the controller and the helper as well.

theIV
  • 25,434
  • 5
  • 54
  • 58
Honza
  • 4,349
  • 2
  • 24
  • 40
  • 1
    Thanks, that makes sense. I have some code that I want to share between two controllers. I'll create a new module and include that. – John Topley Jan 17 '09 at 19:28
  • That's the best approach indeed – ggomeze Jan 27 '11 at 13:29
  • 2
    Is it really about sharing between two controllers? Or between controller and view? I think the latter. So gamecreature's way (@template, view_context) looks correct to me. – Pascal May 02 '11 at 05:36
  • My funky redirect methods are in helpers. I need them from my controllers. I don't think this is bad. – Victor Pudeyev Jun 23 '12 at 01:19
  • 2
    You say it's undesirable to include helper methods in the controller because UI code and controller code should be separate. But what if you are doing filtering and you obviously need to access the params hash in the controller and view and sometimes you need to call methods in the view and controller to access params variables. So what would you do in that circumstance? – JohnMerlino Apr 02 '13 at 21:06
31

if you need to share a method between a controller and helper/view, you can just define via 'helper_method' in the top of the controller:

class ApplicationController < ActionController::Base
  helper_method :my_shared_method
  ...

  def my_shared_method
    #do stuff
  end
end

hope that helps

ben
  • 311
  • 3
  • 2
  • 2
    The line `helper_method :my_shared_method` does *not* need to be at "the top".. it can go anywhere, and I like it best immediately above the definition (`def my_shared_method`). – user664833 May 10 '12 at 02:06
29

Helper Methods from Controllers

One way to get at your helper methods is simply to include your helper file.

include LoginHelper
cool_login_helper_method(x,y,z)

This brings all the methods from that helper module into scope in your controller. That's not always a good thing. To keep the scope separate, create an object, imbue it with the powers of that helper, and use it to call the methods:

login_helper = Object.new.extend(LoginHelper)
login_helper.cool_login_helper_method(x,y,z)

Helper :all

helper :all makes all of your helper methods from all of your helper modules available to all of your views, but it does nothing for your controllers. This is because helper methods are designed for use in views and generally shouldn't be accessed from controllers. In newer versions of Rails, this option is always on for every controller by default.

Adrian Dunston
  • 2,950
  • 4
  • 24
  • 23
7

For Rails 3, use the view_context method in your controller:

def foo
  view_context.helper_method
  ...

Here's an example: http://www.christopherirish.com/2011/10/13/no-view_context-in-rails-3-1-changes/

B Seven
  • 44,484
  • 66
  • 240
  • 385
5

The time when I find this to be most needed is for writing the flash, or custom error checkers. Its nice to use things like link_to helpers in the flash message under some circumstances. I use the following solution to get ActionView helpers into the controller. Be advised that as was mentioned above, this breaks the MVC separation, so if anyone else has a better idea, let me know!

Below ApplicationController add this:

class Something
  include Singleton
  include ActionView::Helpers::UrlHelper
end

and inside the ApplicationController, add

def foo
  Something.instance
end

and finally, in the controller where you want to access the helper code:

messages << "<li class='error'>Your have an Error!<%= foo.link_to('Fix This', some_path) %></li>"

Hope that helps in some way!

Scott Miller
  • 2,298
  • 3
  • 21
  • 24
5

It is probably cleaner to use the helpers method:

class FooController < ActionController::Base
  def action
    self.class.helpers.helper_method arg
  end
end
Antonio Tapiador
  • 4,326
  • 1
  • 15
  • 8
4

Any helper can be accessed using @template variable in the controller.

@template.my_super_helper

BitOfUniverse
  • 5,903
  • 1
  • 34
  • 38
3

Controller can't access helper methods automatically. We must include them in app controller.

module ApplicationHelper

 def hello_message
    "Hello World"
 end

end

class ApplicationController < ActionController::Base

  include ApplicationHelper

  def message
     hello_message
  end

end

Nitin
  • 31
  • 3
2

Helpers are to be used with templates, ie. views, not in controllers. That's why you can't access the method. If you'd like to share a method between two controllers, you'd have to define it in ApplicationController, for instance. helper :all says that any method you define in any helper file in app/helpers directory will be available to any template.

Milan Novota
  • 15,506
  • 7
  • 54
  • 62
1

There are two ways to do this: either to create a module or use @template variable. Check this out for more details http://www.shanison.com/?p=305

Shanison
  • 2,295
  • 19
  • 26
1

If you change your application_controller.rb file to this...

class ApplicationController < ActionController::Base
  protect_from_forgery with: :exception
  include SessionsHelper
end

...then all helpers will be available to all controllers.

I_do_python
  • 1,366
  • 4
  • 16
  • 31
0

If you only have ApplicationHelper inside your app/helpers folder than you have to load it in your controller with include ApplicationHelper. By default Rails only load the helper module that has the same name as your controller. (e.g. ArticlesController will load ArticlesHelper). If you have many models (e.g. Articles; Posts; Categories) than you have to upload each one in you controller. the docs

Helper

module PostsHelper
    def find_category(number)
        return 'kayak-#{number}'
    end
    def find_other_sport(number)
        "basketball" #specifying 'return' is optional in ruby
    end
end

module ApplicationHelper
    def check_this_sentence
        'hello world'
    end

end

Example Controller

class ArticlesController < ApplicationController
    include ApplicationHelper
    include PostsHelper
    #...and so on...

  def show#rails 4.1.5
    #here I'm using the helper from PostsHelper to use in a Breadcrumb for the view
    add_breadcrumb find_other_sport(@articles.type_activite), articles_path, :title => "Back to the Index"
    #add_breadcrumb is from a gem ... 
    respond_with(@articles)
  end
end
Papouche Guinslyzinho
  • 5,277
  • 14
  • 58
  • 101
0

Please try include SessionsHelper in ApplicationController

class ApplicationController < ActionController::Base
  include SessionsHelper
  ...
end
Prateek Arora
  • 616
  • 8
  • 7