245

I want to use the methods I defined in app/helpers/annotations_helper.rb in my ReportMailer views (app/views/report_mailer/usage_report.text.html.erb). How do I do this?

Based on this guide it seems like the add_template_helper(helper_module) method might do what I want, but I can't figure out how to use it.

(BTW, is there a reason you get access to a different set of helpers in mailer views? This is pretty annoying.)

Koen.
  • 25,449
  • 7
  • 83
  • 78
Tom Lehman
  • 85,973
  • 71
  • 200
  • 272
  • similar one - http://amolnpujari.wordpress.com/2013/12/27/highlight-changes-being-made-on-activerecord-object-inside-mail/ – Amol Pujari Dec 27 '13 at 11:33

8 Answers8

343

In the mailer class that you are using to manage your emails:

class ReportMailer < ActionMailer::Base
  add_template_helper(AnnotationsHelper)

  ...
end
Daniel Magliola
  • 30,898
  • 61
  • 164
  • 243
Mark Connell
  • 3,739
  • 1
  • 16
  • 11
  • 4
    Doesn't work for me in this case (Rails 3.2.8): I have a method defined in ApplicationController and make it a helper by helper_method :my_helper_wannabe, but the method "my_helper_wannabe" doesn't become available in mailer. – JNN Nov 07 '12 at 07:23
  • See Duke's answer below for how to handle in Rails 3. – Chris Peters Nov 21 '12 at 01:36
  • This worked for me in Rails 3.2.13. One thing to note: I needed to restart my server before the change went into affect. – Blake May 15 '13 at 14:00
  • 1
    I thought these were supposed to be automatically included in Rails 4? http://guides.rubyonrails.org/action_mailer_basics.html#using-action-mailer-helpers – gabeodess Jan 28 '15 at 22:21
  • Works in Rails 3.2.18 without restart. – Fernando Kosh Jul 27 '15 at 21:21
  • 8
    This is an ancient answer but just chiming in to say this worked in Rails 5.2 – Archonic Nov 10 '18 at 03:46
  • In rails 5 you can just add "helper :helpername" right after class name – Matiss Feb 14 '19 at 11:53
  • 2
    This finally breaks in Rails 6.1.0.rc1 – Aaron Nov 09 '20 at 21:13
  • 4
    This doesn't work in 6.1. For Rails 6.1, use Duke's answer below: https://stackoverflow.com/questions/1416978/how-to-use-my-view-helpers-in-my-actionmailer-views/6393071#6393071 with ```helper :helpername```. – José M. Gilgado Dec 16 '20 at 06:13
167

In Rails 3, just use the helper method at the top of your ActionMailer class:

helper :mail   # loads app/helpers/mail_helper.rb & includes MailHelper

I just passed in a block, since I only need it in the one Mailer:

helper do
  def host_url_for(url_path)
    root_url.chop + url_path
  end
end

(be sure to set config.action_mailer.default_url_options.)

(and if you use url_for, be sure to pass in :only_path => false)

Shevaun
  • 1,208
  • 12
  • 19
Duke
  • 7,070
  • 3
  • 38
  • 28
  • 3
    This works, but feels akward to re-specify helpers already defined in ApplicationController to individual ActionMailer classes as well. ActionMailer extends ActionController so they come from a common hierarchy. More of a comment on Rails than your solution... – robbie613 May 12 '13 at 23:34
  • 3
    And if the helper is in a namespace you can do `helper :'namespace/mail'` – Jonathon Batson Oct 20 '14 at 04:22
  • if the helper is in a namespace it also accepts just a string (instead of a symbol) `helper 'namespace/mail'` – Pwnrar Nov 17 '16 at 00:04
  • 2
    Works on Rails 5.2! – alexandre-rousseau Jun 08 '18 at 22:03
  • How do you do this when the ActionMailer class is buried in a gem, such as Devise? Putting `<% helper :mail %>` at the top of the mailer view fails with `undefined method 'helper'`. Ideally there would be a way of setting `helper :mail` for *all* Action Mailer mailers… – John Y Jan 11 '21 at 15:29
  • Works on Rails 7.0 ! – TomDogg Jun 02 '23 at 17:34
30

(This is an old question but Rails has evolved so I'm sharing what works for me in Rails 5.2.)

Typically you might want to use a custom view helper in rendering the subject line of an email as well as the HTML. In the case where the view helper is in app/helpers/application_helper.rb as follows:

module ApplicationHelper

  def mydate(time, timezone)
    time.in_time_zone(timezone).strftime("%A %-d %B %Y")
  end

end

I can create a dynamic email subject line and template which both use the helper but I need to tell Rails to use the ApplicationHelper explicitly in apps/mailer/user_mailer.rb in two different ways, as you can see in the second and third lines here:

class UserMailer < ApplicationMailer

  include ApplicationHelper  # This enables me to use mydate in the subject line
  helper :application  # This enables me to use mydate in the email template (party_thanks.html.erb)

  def party_thanks
    @party = params[:party]
    mail(to: 'user@domain.com',
    subject: "Thanks for coming on #{mydate(@party.created_at, @party.timezone)}")
  end

end

I should mention that these two lines work just as well so choose one or the other:

helper :application

add_template_helper(ApplicationHelper)

FWIW, the email template at app/views/user_mailer/party_thanks.html.erb looks like this:

<p>
  Thanks for coming on <%= mydate(@party.created_at, @party.timezone) %>
</p>

And the app/controller/party_controller.rb controller looks like this

class PartyController < ApplicationController
  ...
  def create
    ...
    UserMailer.with(party: @party).party_thanks.deliver_later
    ...
  end
end

I have to agree with OP (@Tom Lehman) and @gabeodess that this all feels quite convoluted given https://guides.rubyonrails.org/action_mailer_basics.html#using-action-mailer-helpers so perhaps I am missing something...

MSC
  • 3,286
  • 5
  • 29
  • 47
29

For all mailers in Rails 3 (setting "application" helper):

# config/application.rb:
...
config.to_prepare do
  ActionMailer::Base.helper "application"
end
Edison Machado
  • 1,410
  • 19
  • 29
27

For Ruby on Rails 4, I had to do 2 things:

(1) As Duke already said, if the helper you want to add is UsersHelper for example, then add

helper :users

to the derived ActionMailer class (e.g. app/mailers/user_mailer.rb)

(2) After that, I got a new error:

ActionView::Template::Error (Missing host to link to! Please provide the :host
parameter, set default_url_options[:host], or set :only_path to true)

To fix this, add the line

config.action_mailer.default_url_options = { :host => 'localhost' }

to each of the config/environments/*.rb files. For config/environments/production.rb, replace localhost with a more appropriate host for the production helper-generated urls.


Q: For #2, why does the mail view need this information, and the regular views do not?

A: Because the regular views don't need to know the host, since all generated links are served from the host they link to. Links that show up in emails are not served from the same host (unless you are linking to hotmail.com or gmail.com, etc.)

Community
  • 1
  • 1
Matt
  • 20,108
  • 1
  • 57
  • 70
23

You can just add in your mailer

helper :application

or whatever helper you need

user1136228
  • 967
  • 9
  • 22
9

This is what I did in rails 6

class ApplicationMailer < ActionMailer::Base
  default from: 'community@example.com'
  layout 'mailer'

  # Add whatever helper you want
  helper :application  

end
stevec
  • 41,291
  • 27
  • 223
  • 311
7

in my case for Rails4, i do like this:

# app/mailers/application_mailer.rb
class ApplicationMailer < ActionMailer::Base
  add_template_helper ApplicationHelper
  ...
end

and

# app/mailers/user_mailer.rb
class AccountMailer < ApplicationMailer
  def some_method(x, y)
  end
end

so that you do not have to specify add_template_helper everywhere.

Yoshi
  • 449
  • 4
  • 9