Ruby 将使用mailer参数的ActionMailer的Rails before_操作

Ruby 将使用mailer参数的ActionMailer的Rails before_操作,ruby,actionmailer,ruby-on-rails-5,Ruby,Actionmailer,Ruby On Rails 5,假设我有一个发送不同电子邮件的邮件程序,但预期将使用相同的参数调用它。我想为所有邮件程序操作处理这些参数。因此,在_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` arg

假设我有一个发送不同电子邮件的邮件程序,但预期将使用相同的参数调用它。我想为所有邮件程序操作处理这些参数。因此,在_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
如何访问
before\u action
块中的
same\u 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
类MyMailer
这就是重构

/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
/mailers/my_mailer.rb
类MyMailer
感觉非最佳状态(
prepare\u mail(相同参数)
在每个操作中重复)

因此,上文提出了建议

解决方案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
下面使用父控制器中缺少方法_的替代解决方案

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

action_mailer中缺少原始方法_,可用作参考:

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

根据赛拉姆的回答,我想到了以下几点,但这感觉有点奇怪,难道在采取行动之前不能用
回调来完成吗

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
classmymailer

此外,我还丢失了操作前的所有酷东西(仅传递
数组除外,等等)

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]
classmymailer打印['some_mail',1,2]


更新


如果您使用的是Rails 5.1,您可以查看一下

只是一个想法-您是否想过直接使用net::STMP发送电子邮件。它将比Action Mailer更具可定制性。从软件工程的角度来看,ActionMailer是一个适配器,您可以配置几种电子邮件传递方法(我目前使用的是3-4),我担心SMTP并不是世界上的全部,所以我想使用ActionMailer。我认为您正在将逻辑部分从控制器移动到层中。最好在mailer类和controller之间添加一个服务层/模型类来实现这一点,而不是覆盖默认的mailer来实现您想要的。@spickermann抱歉忘记了继承,现在添加它。您可以考虑<代码>应用程序邮件> <代码>类似<代码> ActhMaule::Base< /Cord>。在我之前的评论中,我只是解释我不仅仅是通过SMTP直接发送邮件,而且还配置为使用
:file
:cache
:letter\u opener
,等等由ActionMailer很好地包装的传递适配器。您的问题似乎可以通过Rails 5.1中的参数化邮件程序解决(请参阅)问题是,在填写电子邮件标题时有很多不太符合逻辑的
(每个操作都是一样的),但每个单独的mailer_操作都是特定的,我可能想在其中做一些额外的事情(比如附加特定的文件等)。请参阅第一个解决方案。self.send(actiontype,options)哦,对了,这真的很有意义!“对不起,一开始我没意识到它在做什么。”塞拉姆,你真的试过你的第一个建议吗?这很吸引人,但在rails 4.2下,我得到了
ActionView::MissingTemplate:MissingTemplate my_-mailer/generic和“mailer”
。您将如何使用before_-action做到这一点?我试过了,但是没有,我也不知道。事实上,如果您使用的是Rails 5.1,您可以看看它实际上相当不错,可能会有什么进展,但它实际上破坏了大多数现有的测试,在编写本文时,RSpec实际上不太支持它,并且会涉及相当多的代码重写。我们尝试在不同的邮件中使用它,但在撰写本文时,它不如
process\u action
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]