user1735921
user1735921

Reputation: 1389

Delivery method based on condition? Rails

Rails 4.1.4, I have many classes of Mailers, and they all have different delivery methods. Now this has caused me a problem.

In development and test environment when I have delivery_method as :test then if I perform and delivery using the below class then the delivery method becomes :custom_method, even though I have mentioned config.delivery_method = :test in the rails environment files.

class CustomMailer < ActionMailer::Base

  default :delivery_method => :custom_method,
          from: "...",
          reply_to: '...'

  def emailer(emails)
    mail(to: emails, subject: 'test')
  end

end

What is the right way of changing the :custom_method to :test in development and test environments ?

One possible solution I have implemented which works is this:

class CustomMailer < ActionMailer::Base

  DELIVERY_METHOD = Rails.env == 'production' ? :custom_method : :test

  default :delivery_method => DELIVERY_METHOD,
          from: "...",
          reply_to: '...'

  def emailer(emails)
    mail(to: emails, subject: 'test')
  end

end

This works for me but I feel this is not a good way because I have to write this line:

DELIVERY_METHOD = Rails.env == 'production' ? :custom_method : :test

in every Mailer class and that can cause redundancy. Would be great if it could be handled in some common way.

Please note that there are different delivery methods for every Mailer class.

Upvotes: 5

Views: 2044

Answers (2)

EJAg
EJAg

Reputation: 3298

How about create an ApplicationMailer and get all other mailers to inherit from ApplicationMailer? This is the approach in Rails5 now. Code below shows one possible way to define delivery method in children mailers and inherit the selection logic from ApplicationMailer.

class ApplicationMailer < ActionMailer::Base
  SELECTOR = Hash.new { |h,k| h[k] = k }
  DELIVERY_METHOD = Rails.env.production? ? :custom_method : :test ##selection logic, use: env, env variables ...
end

class UserMailer < ApplicationMailer
  SELECTOR[:custom_method] = :sendmail  ##class-specific delivery method
  default delivery_method: SELECTOR[DELIVERY_METHOD]
  ##....
end

Upvotes: 0

gkats
gkats

Reputation: 1322

The approach you're taking certainly works, but I believe that querying Rails.env in your code is an anti-pattern.

You could instead use the application configuration by setting a custom config attribute. Here's an example:

# config/production.rb
Rails.application.configure do
  # by having this configured by an environment variable 
  # you can have different values in staging, 
  # develop, demo, etc.. They all use "production" env.
  config.x.mailer_livemode = ENV['MAILER_LIVEMODE']
end

# config/development.rb
Rails.application.configure do
  config.x.mailer_livemode = false
end

# config/test.rb
Rails.application.configure do
  config.x.mailer_livemode = false
end

# app/mailers/custom_mailer.rb
default delivery_method: Rails.application.config.x.mailer_livemode ? :custom_method : :test

The flexibility is superior. You can have more that one configuration variables working together, set the delivery_method straight in config, etc.

Most importantly, you don't rely on something irrelevant (the Rails.env) for something that concerns how your emails are sent.

Upvotes: 4

Related Questions