【问题标题】:access request parameters in Rails 4.1 mailer preview在 Rails 4.1 邮件预览中访问请求参数
【发布时间】:2018-01-13 08:07:45
【问题描述】:

当我以前使用MailView gem 预览ActionMailer 电子邮件时,我会访问@rack_env 以在不同条件下预览我的电子邮件,例如交付给特定用户或特定区域设置,或具有特定输入。对于新的(ish)ActionMailer::Preview,该实例变量没有被设置,并且params 不存在。有谁知道如何使用ActionMailer::Preview 访问/rails/mailers/:mailer/:action 的GET 参数?

理想情况下,我希望能够请求 /rails/mailers/my_mailer/mymail?user_id=123 并像使用它一样

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

【问题讨论】:

  • 您确定您无权访问params?怎么查?
  • 我用一个说它没有定义的日志语句检查了它。你看到了什么不同的东西吗?
  • op 是对的,只要使用binding.pry 你会看到requestparams 不会引发任何方法错误

标签: ruby-on-rails ruby actionmailer


【解决方案1】:

我想出了一个简单的解决方案,并用blog post on extending ActionMailer 详细说明了它。这是我发现的最简单的解决方案,我唯一担心的是它会如何影响其他控制器的性能。

# 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

【讨论】:

  • 这将获得对完整 request 对象的访问权限。如果您只想要params,请在上面的inject_request 中添加此行ActionMailer::Preview.inject({ params: request.params })
【解决方案2】:

这是我用于特定参数的解决方案(在我的情况下加载特定订单),您可以修改它以使其更通用并适用于任何或所有参数

它在 XXXMailerPreview 类中使用了一个类变量,如果您在 dev 中运行,这应该不是问题。这是必需的,因为至少在 Rails 5 中,预览显示在 IFrame 中,并且添加到预览 url 的 url 参数不会传递给 IFrame url。

具体来说,此示例代码用于 Spree 中的废弃购物车电子邮件,但它也用于任何特定于订单的电子邮件预览

http://localhost:3000/rails/mailers/abandonded_checkout_mailer预览所有电子邮件

mailer_controller_decorator.rb 中,您可以在 Rails 加载后随意加载

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

在你的 XXXMailerPreview 文件中

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

传递给order_for_preview的块用于第一次没有给预览URL提供订单参数的情况

【讨论】:

    【解决方案3】:

    ActionMailer 无权访问控制器参数,因此请将您需要的参数作为参数传递:

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

    然后在你的控制器中:

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

    【讨论】:

    • 如果我定义了一个邮件程序,这将起作用,但我定义了一个预览,如api.rubyonrails.org/v4.1.0/classes/ActionMailer/… 所述。所以实际上我正在定义一个控制器,只是我不知道 ActionMailer::Preview 如何/是否将请求环境暴露给 Preview 子类。
    • ActionMailer::Preview 无权访问任何控制器参数(或任何其他相关参数)。您必须将 id 作为参数传递。将 ActionMailer::Preview 视为邮件程序。
    • 哦,我明白了,所以基本上制作我自己的邮件预览控制器。好吧,如果没有其他人有办法访问这些参数,那将是一个很好的解决方案。谢谢。
    • 没错。 ActionMailer::Preview 旨在用于预览您的邮件模板,而不是用于向您的用户显示预览。您链接到的文档说明您需要在“预览电子邮件”部分下添加虚假数据。
    • 如果此 PR github.com/rails/rails/pull/20646 被 Rails 接受,则可以将参数传递给邮件预览
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-07-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-07-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多