Tuesday, July 11, 2017

Override ActionMailer defaults with a method called from inside any mailer

Leave a Comment

Given we have a custom header set in application.rb as

config.action_mailer.default_options = { 'X-MyCustomHeader' => "Default_value" }

I would like to be able to call a method, such as remove_custom_headerfrom inside any mailer and it have the header removed, or at least set to nil.

Because its a custom header (starting with X-) ActionMailer will allow more than one to be created rather than reseting it as it would with standard headers.

What is the best way to define a method that can overide it?

The issue i have is that is you call headers['X-MyCustomHeader'] = nilinside the mailer method it will not override it, it simply creates a second header where the entry is nil, leaving the original from application.rb on the email.

The only way i can find to override the default set there is to call default 'X-MyCustomHeader' => nil inside the ApplicationMailer (or in any inheriting mailers class'), like below, but not in the method.

    class ApplicatioMailer < ActionMailer::Base        helper :application        default 'X-MyCustomHeader' => nil      end 

but i would like to call this on a method basis, not in the mailer class itself as the app has many many mailer classes and im looking to disable this for one or 2 methods in some of the Mailers.

My current solution is:

      class ApplicatioMailer < ActionMailer::Base         helper :application         default 'X-MyCustomHeader' => Proc.new { @is_disabled ? nil : Rails.config.action_mailer.default_header }          def remove_custom_header           @is_disabled = true         end       end 

and this seems to work as you are using the default call from ActionMailer to override. Now i have tested this and it does work with multiple calls, so the value of @is_disableddoes not seem to persist between mailer calls. I dont understand how the class var works here, in a SuperClass of the mailer that calls it and when no new object of the class is created, but it seems to be null every new call to the ApplicationMailer, so for me it works. However, is this a good solution? Have i missed something obvious? I dont feel comfterable using a class var in this situation, but i can think of another way!

Thanks in advance for any help!

EDIT:: For example, i would like to call in my mailers like so..

    class MyMailer < ApplicatioMailer       def mail_method_one(email)         # my call         remove_custom_header         mail from: a.format, subject: email.subject       end     end 

And if my method above of setting the class var is valid and sane (which i doubt somehow) can someone explain why as i would be interested how it works and will have to justify it to my lead dev! :)

1 Answers

Answers 1

Contrary to what it looks like, @is_disabled is not a class variable, it's an instance variable. Just as the method you defined is defined as an instance class

Note that you're doing...

def mail_method_one(email) 

...not...

def self.mail_method_one(email) 

You can confirm this yourself by stopping execution using the pry gem or some other inspection tool...

def mail_method_one(email)   binding.pry 

And if you examine self you'll see you're in an instance of the mailer.

You do call it as a class method, but that's because action mailer uses method_missing to test if the missing class method is actually an instance method and creates a new instance of MessageDelivery passing the class name, the method name and the arguments, and subsequently calls the method on an instance of the mailer class.

Here's the code where it does that...

  def method_missing(method_name, *args)     if action_methods.include?(method_name.to_s)       MessageDelivery.new(self, method_name, *args)     else       super     end   end 

You can examine the code here... https://github.com/rails/rails/blob/master/actionmailer/lib/action_mailer/base.rb

If You Enjoyed This, Take 5 Seconds To Share It

0 comments:

Post a Comment