Ruby on rails ActionMailer::Base中的元编程

Ruby on rails ActionMailer::Base中的元编程,ruby-on-rails,ruby,metaprogramming,actionmailer,method-missing,Ruby On Rails,Ruby,Metaprogramming,Actionmailer,Method Missing,实际上,我正在创建一个时事通讯massmailling软件,通过该软件,我可以动态创建一个新的邮件列表,上传一个模板,然后从该列表向用户发送一封电子邮件,操作如下: @suscribers.each do |suscriber| NewsletterMailer.delay.send("#{@list.name}_newsletter", suscriber, @newsletter) end (请注意,延迟方法是因为我在后台作业中使用sidekiq) 我试图在NewsletteMai

实际上,我正在创建一个时事通讯massmailling软件,通过该软件,我可以动态创建一个新的邮件列表,上传一个模板,然后从该列表向用户发送一封电子邮件,操作如下:

@suscribers.each do |suscriber|
    NewsletterMailer.delay.send("#{@list.name}_newsletter", suscriber, @newsletter)
end
(请注意,延迟方法是因为我在后台作业中使用sidekiq)

我试图在NewsletteMailer类中重写ActionMailer::Base中缺少的方法_来处理这个逻辑,但它似乎没有被执行。我刚刚收到一个命名错误,上面写着“NewsletterMailer:Class的未定义方法`testing_newsletter'”

我查找了ActionMailer::Base#method _缺少的源代码,我发现它已经在执行一些逻辑,因此我们可以在不调用new的情况下执行_email.deliver的Mailer.name _。此外,此方法受到保护

但是,有没有一种方法我仍然可以从一个在我的NewsletteMailer类中没有硬编码的方法发送电子邮件?有没有办法向ActionMailer控制器动态添加方法


非常感谢。

您可以使用class\u eval动态定义新方法:

class SomeClass
end

[:foo, :bar].each do |name|
  SomeClass.class_eval <<COMMAND
    def self.#{name}
      puts "Hello from #{name}"
    end
COMMAND
end

SomeClass.foo
SomeClass.bar 
class-SomeClass
结束
[:foo,:bar]。每个do |名称|

SomeClass.class\u eval如果您将其定义为
def method\u missing…
,则您已经创建了一个实例方法,但您的代码表明您正在向类本身发送动态消息。如果您想让它像您编写的那样执行,您需要在
newslettemailer
上定义
self.method\u missing


话虽如此,我还是建议你不要使用这种设计。我要记住的想法是,你有行为——所有时事通讯都有的方法和行动——和数据,这些数据描述了任何给定列表和/或其时事通讯的细节。在大多数情况下,它们应该保持独立和不同,代码描述行为,数据库保存数据。为每个邮件列表定义一个新方法是没有意义的,因为您可以使用一个方法
send\u newsletter
,将列表作为参数。

非常感谢。起初,我对您描述的相同设计进行了思考,但我认为它打破了ActionMailer的制作方式,因为即使是几乎相同的行为,模板也不相同,ActionMailer::Base的理念是基于方法名称加载模板。因此,我认为每一份时事通讯都需要自己的方法。但是我发现我可以在mail方法中指定模板名称。知道了这一点,我将重构一切,并使用单一方法发送所有新闻稿。