2015-02-20 12 views
6

Предположим, у меня есть почтовая программа, которая отправляет разные электронные письма, но ожидается, что они будут вызываться с теми же параметрами. Я хочу обработать эти параметры для всех действий почтовой программы. Таким образом, вызов before_action который будет считывать параметры, отправленных метод почтовой программыRails before_action для ActionMailer, который использовал бы аргументы почтовой программы

/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 

Тогда в моем контроллере/услуге я где-то

MyMailer.actionx(*mailer_params).deliver_now 

Как я могу получить доступ к списку same_param аргументов внутри before_action блока ?

EDIT:

Я хочу, чтобы реорганизовать от

/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 
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 

ощущению неоптимальным (prepare_mail(same_params) дублируется в каждом действии)

Поэтому то, что было предложенный выше

+0

только мысль - вы думали только с помощью Net :: STMP напрямую отправлять сообщения электронной почты http://ruby-doc.org/stdlib-2.0.0 /libdoc/net/smtp/rdoc/Net/SMTP.html.Он будет более настраиваемым, чем Action Mailer. – zee

+0

С точки зрения программного обеспечения, ActionMailer является адаптером, и вы можете настроить несколько методов доставки электронной почты (в настоящее время я использую 3-4), я боюсь, что SMTP не все есть в мире, поэтому я хотите использовать ActionMailer. –

+0

Я думаю, что вы перемещаете логическую часть от контроллера в слой. Лучше всего добавить класс уровня обслуживания/класса между классом почтовой программы и контроллером, чтобы добиться этого, а не переопределять почтовую программу по умолчанию для достижения того, чего вы хотите. – Sairam

ответ

5

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] 

The documentation

1

Solution1:

Я хотел бы предложить вам использовать это, если вы не заботитесь о формате

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 

альтернативное решение ниже с использованием method_missing от родительского контроллера

Неправильно поставить свою логику там, но если вы все еще хотите это сделать, вы можете использовать th e method_missing, чтобы поместить свою логику и пропустить методы action1 и action2.

Оригинал method_missing из 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 

https://github.com/rails/rails/blob/c8a18aaf44a84f1ef0df007aa3f8446752dc327d/actionmailer/lib/action_mailer/base.rb#L561-L567

+0

Проблема в том, что существует множество «не-действительно логических», которые состоят в заполнении заголовков электронной почты (и они одинаковы для каждого действия) , но каждое индивидуальное почтовое отправление остается конкретным, и я могу захотеть сделать там лишний материал (например, прикрепление определенного файла и т. д.). –

+0

см. первое решение. self.send (actiontype, options) – Sairam

+0

О, хорошо, что на самом деле имеет смысл! Извините, я не понял, что он делает сначала. –

0

На основании ответа Сайрам, я хотя из следующих, но это чувствует себя немного странно, он не может быть сделано с 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 

Также я потеряю все интересный материал из before_action (пропускание only или except массива и т.д.)