2015-02-20 8 views
6

Angenommen, ich habe einen Mailer, der verschiedene E-Mails sendet, aber voraussichtlich mit den gleichen Parametern aufgerufen wird. Ich möchte diese Parameter für alle Mailer-Aktionen verarbeiten. Also, ein before_action Aufruf, dass die Parameter an die Versandmethode gesendet lesen würdeRails before_action für ActionMailer, der Mailer-Argumente verwenden würde

/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 

Da ist in meinem Controller/Service muss ich irgendwo

MyMailer.actionx(*mailer_params).deliver_now 

Wie kann ich die same_param Argumente Liste innerhalb des before_action Block zugreifen ?

EDIT:

ich von

/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 

Refactoring wollen Und das Refactoring

/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 

Man fühlt sich nicht optimal (prepare_mail(same_params) in jeder Aktion dupliziert)

So was war vorgeschlagen über

+0

nur ein Gedanke - haben Sie daran gedacht, nur mit net :: STMP direkt E-Mails senden http://ruby-doc.org/stdlib-2.0.0 /libdoc/net/smtp/rdoc/Net/SMTP.html.Es wird anpassbarer als Action Mailer. – zee

+0

Aus Sicht der Softwaretechnik ist ActionMailer ein Adapter, und Sie können mehrere E-Mail-Zustellungsmethoden konfigurieren (ich verwende derzeit 3-4), ich fürchte, SMTP ist nicht alles, was es auf der Welt gibt, also ich möchte ActionMailer verwenden. –

+0

Ich denke, Sie bewegen Logikteil vom Controller in die Schicht. Am besten ist es, eine Serviceschicht/Modellklasse zwischen Mailer-Klasse und Controller hinzuzufügen, um dies zu erreichen, anstatt den Standard-Mailer zu überschreiben, um das zu erreichen, was Sie wollen. – Sairam

Antwort

5

Action verwendet das AbstractController::Callbacks Modul. Ich habe es versucht und es scheint für mich zu funktionieren.

Der Code

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] 

The documentation

1

Solution1:

Ich würde vorschlagen, dass Sie diese verwenden, wenn Sie über das Format unter Verwendung method_missing von der übergeordneten Steuerung

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 

alternative Lösung ist es egal,

Es ist nicht richtig, deine Logik dort zu platzieren, aber wenn du es immer noch tun willst, kannst du th verwenden e method_missing, um Ihre Logik dort zu platzieren und die Methoden action1 und action2 zu überspringen.

Original-method_missing von action_mailer, die als Referenz verwendet werden können:

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

+0

Das Problem ist, es gibt eine Menge "nicht-wirklich Logik", die darin besteht, die E-Mail-Header zu füllen (und sie sind für jede Aktion gleich) , aber jede einzelne mailer_action bleibt spezifisch, und ich möchte vielleicht zusätzliche Sachen dort hineinbringen (wie das Anhängen einer bestimmten Datei usw.) –

+0

siehe die erste Lösung. self.send (aktionstyp, optionen) – Sairam

+0

Ach richtig, das macht Sinn! Entschuldigung war nicht klar, was es zuerst machte. –

0

Basierend auf Sairam der Antwort, die ich zwar aus folgendem aber das fühlt sich ein bisschen komisch, kann es nicht mit getan werden before_action Rückruf?

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 

Auch verliere ich das alles coole Sachen aus before_action (vorbei an einer only oder except Array, etc.)