14

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

/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

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

编辑 :

我想从重构

/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)在每个动作中重复)

因此上面的建议

4

3 回答 3

13

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]

文档


更新

如果您使用的是 Rails 5.1,可以查看ActionMailer::Parameterized

于 2017-01-19T08:46:21.113 回答
1

解决方案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

于 2017-01-15T17:34:48.953 回答
0

根据 Sairam 的回答,我想到了以下内容,但感觉有点奇怪,不能用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数组等)

于 2017-01-15T17:58:04.093 回答