Search code examples
ruby-on-railsrubymetaprogrammingactionmailermethod-missing

Metaprogramming in ActionMailer::Base


I am actually creating a newsletter massmailling software from which I can create a new mailling list on the fly, upload a template, and then send an email to the suscribers from that list doing something like this:

@suscribers.each do |suscriber|
    NewsletterMailer.delay.send("#{@list.name}_newsletter", suscriber, @newsletter)
end

(Note that the delay method is because I use sidekiq for my background jobs)

I have tried to override the method_missing from ActionMailer::Base inside the NewsletterMailer class to handle this logic, but it just doesn't seem to be executed. I just receive a NoMethodError saying "undefined method `testing_newsletter' for NewsletterMailer:Class".

I looked up the ActionMailer::Base#method_missing source code and I see that it is already executing some logic so we can be able to do Mailer.name_of_the_email.deliver without calling new. Also, this method is protected.

But, is there a way I can still send an email from a method that is not hardcoded inside my NewsletterMailer class? Is there a way to add methods dynamically to an ActionMailer controller?

Thanks a lot.


Solution

  • If you've defined it as def method_missing ..., you have created an instance method, but your code indicates you are sending the dynamic message to the class itself. You need to define self.method_missing on NewsletterMailer if you want it to execute as you've written it.

    That being said, I would recommend against this design for your particular case. The idea I would keep in mind is that you have behavior - the methods and actions that all newsletters have in common - and data, which describes the particulars of any given list and/or its newsletter. In most cases, these should remain separate and distinct, with your code describing behavior, and a database holding your data. It makes little sense to define a new method for each mailing list, when you could just have a method send_newsletter that takes the list as an argument.