Metaprogramming in ActionMailer::Base - ruby-on-rails

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.

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.

You can use class_eval to define new methods on the fly:
class SomeClass
end
[:foo, :bar].each do |name|
SomeClass.class_eval <<COMMAND
def self.#{name}
puts "Hello from #{name}"
end
COMMAND
end
SomeClass.foo
SomeClass.bar

Related

RIght way of writing module methods in Ruby

what is right way of writing module? is it only used to stock some peace of code to minimize the number of lines, or is it something much more important than that
I have used and seen ways of writing module, I am working on setting up correct way to define and standardised module. this example is kind of controller code that we use in rails
Way 1 :-
module B
extend ActiveSupport::Concern
def process_items
# do somthing...
#items.pluck(:names)
end
end
Class A
include B
def index
#items = Item.all
#item_names = process_items
end
end
Way 2 :-
module B
extend ActiveSupport::Concern
def process_items(items)
# do somthing...
items.pluck(:names)
end
end
Class A
include B
def index
#items = Item.all
#item_names = process_items(#items)
end
end
Way 1 :-
When I see this independently, its not much readable as I don't know how #items appeared in this method
Unit testing would be hard for method as its dependent
Way 2 :-
Looking at method I can see input is coming we are processing it and returning it back (readablity is good)
Unit testing is easy to this, we wll call method pass what it needs and expect
The way I see modules should be independent, self explanatory, it should be generic so that can be used in any class, kind of helpers. But other way could be dependent on where we use modules
We are using modules like in rails
We use conccern in models, when we call module method we can use self.<field> we don't need to pass anything because instance variable is supposed to be accesssable in every instance method
View helpers are modules I see they put logic into it hard to understand how the variable come from may be instance variable or params, what about making it method which accept somthing and return it back
Concerns on controllers, like the example I have given
I would like to have thoughts on this, what is best approach out of it? is it something which can be standarise or it is more situational or I don't know yet :)
Note: -
I was looking at this question but answer given on this question is no more valid as referenced links are not working.
Right Way to Use Module
The difference here is practically academic, as if you have attr_reader :x then both #x and x will have the same meaning.
It's understood that within a mixin module you will be referencing methods and/or variables that are part of the class or module doing the "mixing in". As such, seeing #x, or in your case, #items, should not come as a real surprise.
If you want to add it as an explicit argument you're sort of missing a lot of the benefits of using a mixin in the first place. You don't need to mix it in at all, you can just use it like B.process_items(...). In other words, your second approach is having an identity crisis. Is it a stand-alone module that includes Concern for no reason, or a weak mixin?
When it comes to testing, you must test the mixin in a module or class which implements the required features. In this case you need either an #items variable, or an items method, and that must have a value of the expected type.
This should be documented somewhere for clarity, but is effectively an implicit contract with anyone using this module.

rspec: Helpers Method on Model undefined method

I'm getting an issue with helpers method included in my model.
I include my helpers as follow:
class Booking < ApplicationRecord
include BookingsHelper
include PaymentsHelper
Both of BookingsHelper and PaymentsHelper have slack_notify function.
So in order to call the good slack_notify function I call this function as below:
BookingsHelper.slack_notify(self)
PaymentsHelper.slack_notify(requester.email, 'danger', 'booking:proceed_payment', e.message)
When I run my test (with rspec) I got:
Failure/Error: BookingsHelper.slack_notify(self)
NoMethodError:
undefined method `slack_notify' for BookingsHelper:Module
And I noticed if I change: BookingsHelper.slack_notify(self) by slack_notify(self) it works but call the slack_notify in PaymentsHelper so I don't really understand what's happening. And if I remove the PaymentHelper it call the good one
If someone could highlight me on this behavior, I would be really interested to understand whats going on
Thanks
You are using Mixin here.
A mixin can basically be thought of as a set of code that can be added
to one or more classes to add additional capabilities without using
inheritance. In Ruby, a mixin is code wrapped up in a module that a
class can include or extend
You do not access helper methods like the static methods but you call them directly, in your example you should call slack_notify directly without having module name before.
When you include two modules which have the same method name then the last one overrides the previous one.
If you do not want it to be overriden then you have to define in the module like that:
def BookingsHelper.slack_notify
// your code
end
and
def PaymentsHelper.slack_notify
// your code
end
see the example about sin and cos here: https://www.tutorialspoint.com/ruby/ruby_modules.htm
Read more about mixins and you will have better understanding of what is going on here.

Rails associated models with a method of the same name

I'm working with a massive legacy code base, so I am looking for advice concerning this particular issue, please, not suggestions of better high-level implementations.
A simplified version of what I'm working with:
class Order < ActiveRecord::Base
has_many :line_items
#other stuff
def balance
#some definition
end
end
class LineItem < ActiveRecord::Base
belongs_to :order
#other stuff
end
module Concerns
module LineItems
module Aggregates
extend ActiveSupport::Concern
#stuff
def balance
#some other definition
end
end
end
end
Order has a method called 'balance,' and a module of LineItem also has a method called 'balance.' It seems that most of the time (in most places in the code base), when specific_line_item.balance is called, it used the method definition under the LineItem module, but there are a couple of places where it instead calls the method from Order.
Is there any way in Ruby/Rails to specify on method call which of these two I'd like to use? OR is there probably something else going on here because Ruby doesn't have method overloading, so the problem I'm describing here isn't possible?
All relevant cases where either method is called are coming from a line_item (i.e. specific_line_item.balance), so I would think it would always choose the method closer to home, rather than making the associative jump and calling Order's 'balance' method without being told to.
EDIT:
Thanks for the responses! It seems I wasn't clear enough with my question. I understand the difference between
Order.first.balance
and
LineItem.first.balance
and that the balance method being called is the one defined within the class for that object. In the situation I'm describing, I observed, in the actual live app environment, that at a place in the code where
LineItem.find(some_id).balance
was called it output not the result that would be computed by the LineItem 'balance' method, but the one from the Order class.
So I had hoped to learn that there's some ruby quirk that might have an object call an associate's method of the same name under some conditions, rather than it's own. But I'm thinking that's not possible, so there's probably something else going on under the covers specific to this situation.
Firstly, ActiveRecord::Concern can change a lot of behaviour and you've left out a lot of code, most crucially, I don't know where it's being injected, but I can make an educated guess.
For a Concern's methods to be available a given object, it must be include'd in the object's class's body.
If you have access to an instance of the Order object, at any point you can call the balance method:
order = Orders.last # grab the last order in your database
order.balance # this will call Order#balance
And if you have the Order then you can also get the LineItem:
order.line_items.first.balance # should call the Concerns:: LineItems::Aggregates#balance
You can open up a Rails console (with rails console) and run the above code to see if it works as you expect. You'll need a working database to get meaningful orders and balances, and you might need to poke around to find a completed order, but Ruby is all about exploration and a REPL is the place to go.
I'd also grep (or ag or ack) the codebase looking for calls to balance maybe doing something like grep -r "(^|\s)\w+\.balance" *, what you want to look for is the word before .balance, that is the receiver of the "balance" message, if that receiver is an Order object then it will call Order#balance and if it is a LineItem object then it will call Concerns:: LineItems::Aggregates#balance instead.
I get the feeling you're not familiar with Ruby's paradigm, and if that's the case then an example might help.
Let's define two simple Ruby objects:
class Doorman
def greet
puts "Good day to you sir!"
end
end
class Bartender
def greet
puts "What are you drinking?"
end
end
Doorman and Bartender both have a greet method, and which is called depends on the object we call greet on.
# Here we instantiate one of each
a_doorman = Doorman.new
a_bartender = Bartender.new
a_doorman.greet # outputs "Good day to you sir!"
a_bartender.greet # outputs "What are you drinking?"
We're still using a method called greet but the receiver is what determines which is called.
Ruby is a "message passing language" and each "method" is not a function but it's a message that is passed to an object and handled by that object.
References
How to use concerns in Rails 4
http://api.rubyonrails.org/classes/ActiveSupport/Concern.html
http://guides.rubyonrails.org/command_line.html#rails-console

Add a method hook that fires after any activerecord method on a model

One of our use cases involves publishing active record models over Drb. It looks like when we do this we are inadvertently leaving connections checked out and as a result we're receiving AR timeouts.
I think this is because of this comment in the active record code:
http://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/ConnectionPool.html
Specifically
"Simply use ActiveRecord::Core#connection as with Active Record 2.1
and earlier (pre-connection-pooling). Eventually, when you're done
with the connection(s) and wish it to be returned to the pool, you
call ActiveRecord::Base.clear_active_connections!. This will be the
default behavior for Active Record when used in conjunction with
Action Pack's request handling cycle."
When we're accessing out models over Drb we're not going through the request cycle so the connection is not getting checked back in.
The same document suggests we need to check these connections back in manually - what I need is a way to hook into all methods on a published model and call "ActiveRecord::Base.clear_active_connections" afterwards.
class Foo < ActiveRecord::Base
#I need this method to be called after every method on this class!
def close_connections
ActiveRecord::Base.close_active_connections
end
end
Closing the connections manually isn't really an option because there are tens of thousands of lines of code and I'd need to go and add "close the connection" after every single one!
You could add this snippet at the end of your class definition..
(instance_methods - Class.new.methods).each do |method|
define_method "#{method}_with_close_connections" do |*args, &block|
self.send "#{method}_without_close_connections", *args, &block
ActiveRecord::Base.close_active_connections
end
alias_method_chain method, :close_connections
end
Highly non-recommended, however. You should probably find another solution.
One potential solution is to use Observers - http://api.rubyonrails.org/v3.2.13/classes/ActiveRecord/Observer.html
You will, however, need an observer for each one of your Models.
Before going down this path though, I would thoroughly evaluate your implementation and find a better way of accessing the connection pool.

How does rails implement before_filter?

I'm interested in how rails implement filters like before_filter.
But after reading the source code, I'm still confused.
I noticed that rails' framework maintains a filter_chain, and run the filters before the target method.
But, I do not understand an important process: how does rails capture a method calling?
I mean, for example, I have a class Dog, and set a before_filter to the method bark.
When I call dog.bark, rails should capture this calling in some way, and run its modified method instead.
However, I do not find such code in the source code.
Can anyone tell me the idea or point out where the code lies?
When you set a before_filter, or any similar filter (think after_filter, around_filter), you're doing so with either a Symbol or a Proc, lambda or block.
before_filter :bark
before_filter Proc.new { |k| k.bark }
The above appends the symbols or blocks to a stack here, by calling set_callback. This builds the 'chain' you're referring to.
Each item in this 'chain' is an instance of the ActiveSupport::Callbacks::Callback class. This class knows
The the method (Symbol) or block it must run (ie. your class' :bark method)
The context which it must run within (ie. your Dog class)
The Callback instances are appended to a ActiveSupport::Callbacks::CallbackChain in __update_callbacks.
When each Callback class is initialized, _compile_filter is run to normalize the filter from the Symbol, Proc, lambda, or block into a common, callable format.
Finally, when the CallbackChain is run, it will call start on each Callback instance, and its at this point that the filter is actually executed within the proper context.
It's important to point out that you would not create a filter like
before_filter dog.bark
this is going to execute dog.bark and pass it's return value to before_filter to be appended to the CallbackChain. The intention is to pass some sort of instruction on to before_filter for Rails to later execute for you. You would instead do something like
before_filter Proc.new { d = Dog.new; d.bark }
The code within the Proc is not executed. when the line above is run by Rails. Instead, Rails is being told to pass the Proc to the CallbackChain. The Proc is the 'instruction' you're passing on to Rails to execute at the appropriate time.
how in the first place does rails know I have called :bark
As for this, let's say your Dog class is simply defined as
class Dog
def bark
end
def eat
end
end
(Though this is a terrible example), you might want to have something like
before_bark :eat
This requires you define the bark callback, and then tell your bark method to run the related bark callbacks.
class Dog
extend ActiveModel::Callbacks
define_callbacks :bark
before_bark :eat
def bark
run_callbacks(:bark) { YOUR BARK CODE HERE }
end
def eat
end
end
You can see how ActiveRecord::Callbacks does this.
This really is a bad example though because you can (and should) just call eat directly from bark, but this should get the point across.
Rails doesn't capture method calls the way you describe. If you look at AbstractController::Base.process it will look up the method to be called for the dispatched action, run the filters and then call the actual method. In other words, your controller method is not called directly, but through this process method.

Resources