Handling non-existent methods in Ruby using method_missing


Created by Stan on 07-04-2023


Have you ever encountered a NoMethodError in your Ruby code when trying to call a method that doesn't exist? For this, Ruby metaprogramming has a solution called method_missing. In this article, we'll explore how to use method missing to handle non-existent method calls and unlock the full potential of Ruby.

method_missing is a special method that gets called when a method is invoked on an object that doesn't exist. Here's a simple example:

class Post
  def method_missing(method_name, *args, &block)
    puts "Method #{method_name} does not exist"
  end
end

post = Post.new
post.some_method #=> Method some_method does not exist

You can customize method_missing to provide specific behavior for certain method calls. For example, let's say you want to greet someone based on the method call. Here's how you can do it:

class Post
  def method_missing(method_name, *args, &block)
    if method_name.to_s.start_with?("hello_")
      puts "Hello, #{method_name.to_s[6..-1].capitalize}!"
    else
      super
    end
  end
end

post = Post.new
post.hello_world #=> Hello, World!
post.hello_john #=> Hello, John!

You can also use method_missing to delegate method calls to other objects. For example, let's say you have multiple objects that have different implementations but you want to provide a consistent interface for all of them:

class Post
  def initialize(post_object)
    @post_object = post_object
  end

  def method_missing(method_name, *args, &block)
    if @post_object.respond_to?(method_name)
      @post_object.send(method_name, *args, &block)
    else
      super
    end
  end
end

class BlogPost
  def title
    "My Blog Post"
  end
end

class ForumPost
  def subject
    "My Forum Post"
  end
end

blog_post = BlogPost.new
forum_post = ForumPost.new

post1 = Post.new(blog_post)
puts post1.title #=> My Blog Post

post2 = Post.new(forum_post)
puts post2.title #=> Method 'title' does not exist

For even more control, you can use the respond_to_missing? method in conjunction with method_missing. This allows you to dynamically generate methods based on the method call. Here's an example:

class Post
  def respond_to_missing?(method_name, include_private = false)
    method_name.to_s.start_with?("find_by_") || super
  end

  def method_missing(method_name, *args, &block)
    if method_name.to_s.start_with?("find_by_")
      attribute = method_name.to_s.gsub("find_by_", "")
      Post.where(attribute.to_sym => args[0])
    else
      super
    end
  end
end

class ActiveRecord
  def self.where(attribute)
    puts "Querying #{attribute}"
  end
end

post = Post.new
post.find_by_title("My Post") #=> Querying title

method_missing is a powerful tool in Ruby metaprogramming that allows you to handle non-existent method calls in a flexible and customizable way. By using method missing, you can provide consistent interfaces for multiple objects, generate methods dynamically, and much more.



Related Posts