简体   繁体   中英

access request parameters in Rails 4.1 mailer preview

When I used to use the MailView gem to preview ActionMailer emails, I would access @rack_env to preview my emails under different conditions, eg delivery to a specific user or in a specific locale, or with specific inputs. With the new(ish) ActionMailer::Preview that instance variable isn't being set, and params doesn't exist. Does anyone know how to access the GET params to /rails/mailers/:mailer/:action with ActionMailer::Preview ?

Ideally I'd like to be able to request /rails/mailers/my_mailer/mymail?user_id=123 and use it like

class MyMailerPreview < ActionMailer::Preview
  def mymail
    MyMailer.mymail(User.find(params[:user_id]))
  end
end

ActionMailer does not have access to the controller params, so pass the params you need as arguments instead:

class MyMailerPreview < ActionMailer::Preview
  def mymail(user_id)
    MyMailer.mymail(User.find(user_id))
  end
end

Then in your controller:

MyMailerPreview.mymail(params[:user_id]).deliver

I came up with a simple solution to this and detailed it with a blog post on extending ActionMailer . It's the easiest solution that I've found, my only concern would be how it may impact performance for other controllers.

# config/initializers/mailer_injection.rb

# This allows `request` to be accessed from ActionMailer Previews
# And @request to be accessed from rendered view templates
# Easy to inject any other variables like current_user here as well

module MailerInjection
  def inject(hash)
    hash.keys.each do |key|
      define_method key.to_sym do
        eval " @#{key} = hash[key] "
      end
    end
  end
end

class ActionMailer::Preview
  extend MailerInjection
end

class ActionMailer::Base
  extend MailerInjection
end

class ActionController::Base
  before_filter :inject_request

  def inject_request
    ActionMailer::Preview.inject({ request: request })
    ActionMailer::Base.inject({ request: request })
  end
end

Here's a solution I use for a specific parameter (in my case to load a specific order), you could modify this to make it more generic and work for any or all parameters

It uses a class variable in the the XXXMailerPreview class, which shouldn't be a problem if you are running in dev. This is required because at least in Rails 5 the previews are shown in an IFrame and the url params added to the preview url are not passed to the IFrame urls.

Specifically this example code was for Abandoned Cart emails in Spree but it is also used for any order specific email preview

Preview all emails at http://localhost:3000/rails/mailers/abandonded_checkout_mailer

In mailer_controller_decorator.rb which you can load anyway you want after Rails is loaded

module MailerPreviewOrderNumber
  def set_order_number(order_number)
    @order_number = order_number
  end

  def get_order_number
    @order_number
  end

  def order_for_preview
    order_number = get_order_number
    order = Spree::Order.find_by(:number => order_number) if order_number.present?
    order = yield if order.blank?
    order
  end

end

Rails::MailersController.class_eval do
  before_action :save_order_number, only: [:preview]

  def save_order_number
    if @preview.present? && @preview.respond_to?(:set_order_number)
      @preview.set_order_number(params[:order]) if params[:order].present?
    end
  end
end

And in your XXXMailerPreview file

class AbandondedCheckoutMailerPreview < ActionMailer::Preview
  extend MailerPreviewOrderNumber

  def abandoned_checkout_email
    if Rails.env.development?
      order = self.class.order_for_preview do
        Spree::Order.order(updated_at: :desc).last
      end
      AbandonedCheckoutMailer.abandoned_checkout_email(order)
    end
  end
end

The block passed to order_for_preview is used in the case that no order param is provided to the preview URL the first time

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM