Rails - How to use a Helper Inside a Controller
Asked Answered
O

10

240

While I realize you are supposed to use a helper inside a view, I need a helper in my controller as I'm building a JSON object to return.

It goes a little like this:

def xxxxx

   @comments = Array.new

   @c_comments.each do |comment|
   @comments << {
     :id => comment.id,
     :content => html_format(comment.content)
   }
   end

   render :json => @comments
end

How can I access my html_format helper?

Osset answered 26/2, 2011 at 22:31 Comment(2)
you may want to consider @grosser's answer, it's much more complete.Aten
I know this is old but... what's wrong with plain ruby classes? :pUncinate
S
227

Note: This was written and accepted back in the Rails 2 days; nowadays grosser's answer is the way to go.

Option 1: Probably the simplest way is to include your helper module in your controller:

class MyController < ApplicationController
  include MyHelper
    
  def xxxx
    @comments = []
    Comment.find_each do |comment|
      @comments << {:id => comment.id, :html => html_format(comment.content)}
    end
  end
end

Option 2: Or you can declare the helper method as a class function, and use it like so:

MyHelper.html_format(comment.content)

If you want to be able to use it as both an instance function and a class function, you can declare both versions in your helper:

module MyHelper
  def self.html_format(str)
    process(str)
  end
    
  def html_format(str)
    MyHelper.html_format(str)
  end
end
Smocking answered 26/2, 2011 at 23:9 Comment(7)
Thanks but I'm a little confused. Right now my helper is in /app/helpers/application_helper.rb ... ANd you're suggesting I should move the helper to ApplicationController?Osset
I added 'include ApplicationHelper' to my application_controller but that errors with 'NoMethodError (undefined method `html_format' for ApplicationHelper:Module):'Osset
@Osset Looks like you've figured it out, but I tweaked my answer a little, hopefully making things clearer. In the first version, you can just use html_format - you only need MyHelper.html_format in the second.Smocking
This does not work when the helper method you want to use make use of view methods such as link_to. Controllers don't have access to these methods and most of my helpers use these methods. Also, including the helper into the controller exposes all the helper's methods as publicly accessible actions which is not good. view_context is the way to go in Rails 3.Flyspeck
@GregT - Hadn't seen grosser's answer before, as it came in a bit after the fact, but I like it better too. He just got my upvote.Smocking
@GregT Thanks for your comment. I had similar issues and view_context is just the magic I needed!Yenta
Good stuff. Though in Ruby, you don't need to use the return keyword, since the last line is the returned value.Birecree
O
356

You can use

  • helpers.<helper> in Rails 5+ (or ActionController::Base.helpers.<helper>)
  • view_context.<helper> (Rails 4 & 3) (WARNING: this instantiates a new view instance per call)
  • @template.<helper> (Rails 2)
  • include helper in a singleton class and then singleton.helper
  • include the helper in the controller (WARNING: will make all helper methods into controller actions)
Ogg answered 22/6, 2012 at 18:0 Comment(9)
This answer is even better! In rails 3, simply calling view_context.helper_function is simple and works great. ActionController::Base.helpers.helper_function is equally good.Zilvia
Thank you for introducing me to view_context! Just what's needed here, shame yours isn't the accepted answer!Auer
I like the accepted answer, if the module is limited to items that are needed in that controller. Functions being included in the controller are not a problem as long as your routes are not set up to match everything, ie, no catch all routes. view_context adds more typing, if you need it a lot. Depends on the situation.Arthro
Just to add to everyone else's pleasure - view_context :+1:Bove
WARNING: Don't use view_context. It'll instantiate a new view instance per call...Napiform
ActionController::Base.helpers.helper_function doesn't seem to work. I get NoMethodError - undefined method spell_date_and_time' for #<ActionView::Base:0x007fede56102d0>: when trying to call ActionController::Base.helpers.spell_date_and_time() in a controller method. calling view_context.spell_date_and_time() does work however.Gavelkind
rails 5: simply use helpers.helper_function in your controller (github.com/rails/rails/pull/24866)Fingerprint
The comment about using helpers.helper_function is the only one that worked for me (Rails 5).Concentrated
@Napiform Can you please elaborate. Creating a new view instance per call, does that mean our view layer is computed twice?Medorra
S
227

Note: This was written and accepted back in the Rails 2 days; nowadays grosser's answer is the way to go.

Option 1: Probably the simplest way is to include your helper module in your controller:

class MyController < ApplicationController
  include MyHelper
    
  def xxxx
    @comments = []
    Comment.find_each do |comment|
      @comments << {:id => comment.id, :html => html_format(comment.content)}
    end
  end
end

Option 2: Or you can declare the helper method as a class function, and use it like so:

MyHelper.html_format(comment.content)

If you want to be able to use it as both an instance function and a class function, you can declare both versions in your helper:

module MyHelper
  def self.html_format(str)
    process(str)
  end
    
  def html_format(str)
    MyHelper.html_format(str)
  end
end
Smocking answered 26/2, 2011 at 23:9 Comment(7)
Thanks but I'm a little confused. Right now my helper is in /app/helpers/application_helper.rb ... ANd you're suggesting I should move the helper to ApplicationController?Osset
I added 'include ApplicationHelper' to my application_controller but that errors with 'NoMethodError (undefined method `html_format' for ApplicationHelper:Module):'Osset
@Osset Looks like you've figured it out, but I tweaked my answer a little, hopefully making things clearer. In the first version, you can just use html_format - you only need MyHelper.html_format in the second.Smocking
This does not work when the helper method you want to use make use of view methods such as link_to. Controllers don't have access to these methods and most of my helpers use these methods. Also, including the helper into the controller exposes all the helper's methods as publicly accessible actions which is not good. view_context is the way to go in Rails 3.Flyspeck
@GregT - Hadn't seen grosser's answer before, as it came in a bit after the fact, but I like it better too. He just got my upvote.Smocking
@GregT Thanks for your comment. I had similar issues and view_context is just the magic I needed!Yenta
Good stuff. Though in Ruby, you don't need to use the return keyword, since the last line is the returned value.Birecree
R
85

In Rails 5 use the helpers.helper_function in your controller.

Example:

def update
  # ...
  redirect_to root_url, notice: "Updated #{helpers.pluralize(count, 'record')}"
end

Source: From a comment by @Markus on a different answer. I felt his answer deserved it's own answer since it's the cleanest and easier solution.

Reference: https://github.com/rails/rails/pull/24866

Royo answered 4/11, 2016 at 0:13 Comment(1)
Feels a bit weird that in console you'd call helper in singular and in controller it's plural.Gish
P
10

My problem resolved with Option 1. Probably the simplest way is to include your helper module in your controller:

class ApplicationController < ActionController::Base
  include ApplicationHelper

...
Preconscious answered 26/2, 2016 at 16:11 Comment(1)
Only downside that it adds controller actions with the name of the helper functions. But tbh, I do that, too :)Furnivall
H
9

In general, if the helper is to be used in (just) controllers, I prefer to declare it as an instance method of class ApplicationController.

Hawfinch answered 22/3, 2014 at 20:48 Comment(1)
As a protected methodAgosto
B
8

Before Rails 5, you have to include the helper module.

In newer versions, you can use helpers in your controller with the helpers (plural) object.

  class UsersController
    def index
      helpers.my_helper_method_name(even_pass_arg_here)
    end
  end

https://www.rubyguides.com/2020/01/rails-helpers/

Barye answered 2/4, 2021 at 8:13 Comment(0)
W
4

In Rails 5+ you can simply use the function as demonstrated below with simple example:

module ApplicationHelper
  # format datetime in the format #2018-12-01 12:12 PM
  def datetime_format(datetime = nil)
    if datetime
      datetime.strftime('%Y-%m-%d %H:%M %p')
    else
      'NA'
    end
  end
end

class ExamplesController < ApplicationController
  def index
    current_datetime = helpers.datetime_format DateTime.now
    raise current_datetime.inspect
  end
end

OUTPUT

"2018-12-10 01:01 AM"
Welldressed answered 9/12, 2018 at 19:43 Comment(0)
H
4

In rails 6, simply add this to your controller:

class UsersController < ApplicationController
  include UsersHelper
  
  # Your actions

end

Now the user_helpers.rb will be available in the controller.

Holcombe answered 1/2, 2021 at 5:52 Comment(1)
This works in mailers too, unlike calling via helpers (see https://mcmap.net/q/119320/-access-helpers-from-mailer).Kyles
D
3

One alternative missing from other answers is that you can go the other way around: define your method in your Controller, and then use helper_method to make it also available on views as, you know, a helper method.

For instance:


class ApplicationController < ActionController::Base

private

  def something_count
    # All other controllers that inherit from ApplicationController will be able to call `something_count`
  end
  # All views will be able to call `something_count` as well
  helper_method :something_count 

end
Derogatory answered 15/9, 2020 at 14:37 Comment(1)
No idea how they missed this simple line which i was looking for as well :DAngie
C
0
class MyController < ApplicationController
    # include your helper
    include MyHelper
    # or Rails helper
    include ActionView::Helpers::NumberHelper

    def my_action
      price = number_to_currency(10000)
    end
end

In Rails 5+ simply use helpers (helpers.number_to_currency(10000))

Confocal answered 8/10, 2018 at 16:2 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.