Suppose I have a mailer that sends different emails, but is expected to be called with the same parameters. I want to process those parameters for all mailer actions. So, calling a before_action
that would read the parameters sent to the mailer method
/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
Then in my controller/service I do somewhere
MyMailer.actionx(*mailer_params).deliver_now
How can I access the same_param
arguments list inside the before_action
block ?
EDIT :
I want to refactor from
/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
And this 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-optimal (prepare_mail(same_params)
duplicated in every action)
Hence what was suggested above
ActionMailer uses the AbstractController::Callbacks
module. I tried it and it seems to work for me.
The 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
UPDATE
If you're using Rails 5.1, you can have a look at ActionMailer::Parameterized
Solution1:
I would suggest you use this if you do not care about the format
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 solution below using method_missing from the parent controller
Its not right to put your logic there, but if you still want to do it, you can use the method_missing to put your logic there and skip the action1 and action2 methods.
Original method_missing from action_mailer which can be used as a reference:
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With