2015-02-20 13 views
6

Supponiamo che abbia un mailer che invia email diverse, ma che è previsto che venga chiamato con gli stessi parametri. Voglio elaborare quei parametri per tutte le azioni del mailer. Quindi, chiamare un before_action che leggere i parametri inviati al metodo mailerRails before_action per ActionMailer che utilizza gli argomenti del 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 

Poi, nel mio controller/servizio che faccio qualche

MyMailer.actionx(*mailer_params).deliver_now 

Come posso accedere alla lista same_param argomenti all'interno del blocco before_action ?

EDIT:

voglio refactoring da

/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 

E questo 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 

Feels non ottimale (prepare_mail(same_params) duplicati in ogni azione)

Quindi quello che era suggerito sopra

+0

solo un pensiero - avete pensato di utilizzare solo Net :: SMTP direttamente per inviare messaggi di posta elettronica http://ruby-doc.org/stdlib-2.0.0 /libdoc/net/smtp/rdoc/Net/SMTP.html.Sarà più personalizzabile di Action Mailer. – zee

+0

Dal punto di vista dell'ingegneria del software, ActionMailer è un adattatore, e puoi configurare diversi metodi di consegna delle email (attualmente sto usando 3-4), temo che SMTP non sia tutto ciò che c'è nel mondo, quindi voglio usare ActionMailer. –

+0

Penso che stai spostando la parte logica dal controller al livello. È meglio aggiungere un livello di servizio/classe del modello tra la classe mailer e il controller per ottenere ciò, piuttosto che sovrascrivere il mailer predefinito per ottenere ciò che si desidera. – Sairam

risposta

5

ActionMailer utilizza il modulo AbstractController::Callbacks. L'ho provato e sembra funzionare per me.

Il codice

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

Soluzione1:

Vorrei suggerire di utilizzare questo se non vi interessa sul formato

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 

soluzione alternativa di seguito utilizzando method_missing dal controller genitore

Non è giusto mettere la tua logica lì, ma se vuoi ancora farlo, puoi usare e method_missing per mettere la tua logica lì e saltare i metodi action1 e action2.

method_missing originale dal action_mailer che può essere usato come riferimento:

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

Il problema è che c'è molto 'not-really logic' che consiste nel riempire le intestazioni delle e-mail (e sono le stesse per ogni azione) , ma ogni singola mailer_action rimane specifica e potrei voler fare cose extra lì (come allegare un file specifico, ecc.) –

+0

vedere la prima soluzione. self.send (tipo di azione, opzioni) – Sairam

+0

Oh giusto che abbia davvero senso! Scusa, non ho capito cosa stava facendo in un primo momento. –

0

in base alla risposta del Sairam ho pensato di quanto segue, ma che si sente un po 'strano, può non essere fatto con before_action callback ??

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 

Anche io perdono tutta la roba fresca da before_action (passando un only o except array, ecc)

Problemi correlati