Ruby : Method Missing : How to leverage this feature?

Ruby provides you with a way to handle the situation when your clients try to send a message that your object cannot respond to. Almost every library you use in Ruby has this method implemented to handle such scenario in well defined way.

method_missing(method_name, *arg)

When you send a message to an object, the object executes the first method it finds on its method lookup path with the same name as the message. If it fails to find any such method, it raises a NoMethodError exception – unless you have provided the object with a method called method_missing. The method_missing method is passed the symbol of the non-existent method, an array of the arguments that were passed in the original call and any block passed to the original method.

method_missing is in part a safety net: It gives you a way to intercept unanswerable messages and handle them gracefully

class Test
 def print 
   p 'My name is shiva'
 end

 def method_missing(method_name, *args)
   p "#{method_name} is not defined"
 end
end

Test.new.undefined_method
# output: "undefined_method is not defined"

A well known example of this is ActiveRecord dynamic finders. For example, if your User has an email attribute, you can User.find_by_email('joe@example.com') even though User nor ActiveRecord::Base have defined it.

are methods defined in mailer @instance_methods or @@class_methods?

In the source (https://github.com/rails/rails/blob/master/actionmailer/lib/action_mailer/base.rb), Rails uses method_missing to create a new instance of the ActionMailer. Here’s the relevant excerpt from the source:

# inside ActionMailer::Base
def method_missing(method_name, *args) # :nodoc:
  if respond_to?(method_name)
    new(method_name, *args).message
  else
    super
  end
end

Answer:

-> If method is defined as @instance_method in mailer, then when you invoke the method as class method, since @@class_method of that name is not defined,  NoMethodError exception is thrown (only if method_missing method is not defined in that class).

Since, there is ‘method_missing’ method defined in ActionMailer::Base, it grabs the control and instantiates new YourMailer object and tries to invoke the same message in that instance. If successful your email is sent. Else, again ‘NoMethodError’ exception is thrown.

Sources:

http://rubylearning.com/satishtalim/ruby_method_missing.html

http://technicalpickles.com/posts/using-method_missing-and-respond_to-to-create-dynamic-methods/

http://stackoverflow.com/questions/17088619/how-can-you-call-class-methods-on-mailers-when-theyre-not-defined-as-such

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s