对于将使用邮件程序参数的ActionMailer的Rails before_action

假设我有一个邮件发送不同的电子邮件,但预计将使用相同的参数调用。 我想为所有邮件程序操作处理这些参数。 因此,调用before_action将读取发送到邮件程序方法的参数

 /mailers/my_mailer.rb class MyMailer < ApplicationMailer before_filter do |c| # c.prepare_mail # Will fail, because I need to pass `same_param` arguments # # I want to send the original arguments # c.prepare_mail(same_param) # How do I get `same_param` here ? end def action1(same_param) # email view is going to use @to, @from, @context method_only_specific_to_action1 end def action2(same_param) # email view is going to use @to, @from, @context method_only_specific_to_action2 end private def prepare_mail(same_params) @to = same_params.recipient @from = same_params.initiator @context = same_params.context end end 

然后在我的控制器/服务中我做某个地方

 MyMailer.actionx(*mailer_params).deliver_now 

如何访问before_action块中的same_param参数列表?

编辑:

我想重构一下

 /mailers/my_mailer.rb class MyMailer < ApplicationMailer def action1(same_param) @to = same_params.recipient @from = same_params.initiator @context = same_params.context method_only_specific_to_action1 end def action2(same_param) @to = same_params.recipient @from = same_params.initiator @context = same_params.context method_only_specific_to_action2 end def actionx ... end end 

而这个重构

 /mailers/my_mailer.rb class MyMailer < ApplicationMailer def action1(same_param) prepare_mail(same_params) method_only_specific_to_action1 end def action2(same_param) prepare_mail(same_params) method_only_specific_to_action2 end def actionx ... end private def prepare_mail(same_params) @to = same_params.recipient @from = same_params.initiator @context = same_params.context end end 

感觉非最佳( prepare_mail(same_params)在每个动作中重复)

因此,上面提出了什么

ActionMailer使用AbstractController::Callbacks模块。 我尝试过它似乎对我有用。

代码

 class MyMailer < ApplicationMailer def process_action(*args) # process the args here puts args super end def some_mail(*args) end end MyMailer.some_mail(1, 2) #=> prints ['some_mail', 1, 2] 

文档


UPDATE

如果你正在使用Rails 5.1,你可以看一下ActionMailer :: Parameterized

解决方法1:

如果你不关心格式,我建议你使用它

 MyMailer.generic("actionx", *mailer_params).deliver_now def generic(actiontype, *mailer_params) # custom logic goes here to construct the to, from, etc., # new_options from custom logic self.send(actiontype, new_options) end 

下面使用来自父控制器的method_missing的替代解决方案

将逻辑放在那里是不对的,但是如果你仍然想要这样做,你可以使用method_missing将你的逻辑放在那里并跳过action1和action2方法。

来自action_mailer的原始method_missing,可用作参考:

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

https://github.com/rails/rails/blob/c8a18aaf44a84f1ef0df007aa3f8446752dc327d/actionmailer/lib/action_mailer/base.rb#L561-L567

根据Sairam的回答我虽然有以下但感觉before_action ,难道不能用before_action回调吗?

 class MyMailer < ApplicationMailer # Simulation of before_action callback that would support passing the *args to the callback method def self.method_missing(method_name, *args) method_name = :"#{method_name.to_s}_headers_prefilled" if action_methods.include?(method_name) mailer = MyMailer.generic(*args) # The before_action callback that passes *args mailer.send(method_name, *args) # The action itself else super end end def generic(*mailer_params) # custom logic goes here to construct the headers to, from, etc., end def action1_headers_prefilled(mailer_params) # Logic only relevant for action1 end 

我也失去了来自before_action的所有很酷的东西(传递一个onlyexcept数组等)