Ruby for Newbies: Missing Methods


Ruby is a one of the most popular languages used on the web. We’re running a Session here on Nettuts+ that will introduce you to Ruby, as well as the great frameworks and tools that go along with Ruby development. In this episode, we’re going to look at the too-cool-to-be-true way that Ruby objects deal with methods that don’t exist.

Video Tutorial?

Subscribe to our YouTube and channels to watch more screencasts.

A Problem (and a Solution)

Let’s say your working with a Ruby object. And let’s also say that you aren’t entirely familiar with this object. And let’s also say that you call a method that doesn’t exist on the object.

o =
# NoMethodError: undefined method `some_method' for #<Object:0x00000100939828>

This is less than desirable, so Ruby has an awesome way of allowing us to rescue ourselves from this. Check this out:

class OurClass
  def method_missing (method_name)
    puts "there's no method called '#{method_name}'"

o =
# => there's no method called 'some_method'

We can create a method called method_missing in our class. If the object we’re calling the method on doesn’t have the method (and doesn’t inherit the method from another class or module), Ruby will give us one more chance to do something useful: if the class has a method_missing method, we’ll hand the information about the method cal to method_missing and let it sort the mess out.

Well, that’s great; we’re no longer getting an error message.

A Better Use

But stop and think about this for a second. First of all: no, we’re not getting an error message any more, but we aren’t getting something useful. It’s hard to say what useful would be in this case, because out method name doesn’t suggest anything. Second of all, this is pretty powerful, because it allows you to basically pass any method to an object and get an intelligent result.

Let’s do something that makes more sense; start with this:

class TutsSite
  attr_accessor :name, :tutorials
  def initialize name = "", tuts = []
    @name = name
    @tutorials = tuts
  def get_tuts_about_javascript do |tut|
      tut[:tags].include? "javascript"
  def get_tuts_by_jeffrey_way do |tut|
      tut[:author] == "Jeffrey Way"

Here you see a little class for a tutorial website. When creating a new website object, we pass it a name and an array of tutorials. We expect tutorials to be hashes in the following form:

{ title: "Some title", author: "the author", tags: ["array", "of", "tags"] # Ruby 1.9

# OR

{ :title => "Some title", :author => "the author", :tags => ["array", "of", "tags"] # Ruby 1.8

We expect symbols as the keys; notice that if you’re not using Ruby 1.9, you’ll have to use the bottom format for your hashes (both work in 1.9)

Then, we’ve got two helper functions that allow us to get only the tutorial that have a JavaScript tag, or only the tutorials by Jeffrey Way. These are useful for filtering the tutorials … but they don’t give us too many options. Of course, we could make methods named get_tuts_with_tag and get_tuts_by_author that take parameters with the tag or author name. However, we’re going to go a different route: method_missing.

As we saw, method_missing gets the attempted method name as a parameter. What I didn’t mention is that it’s a symbol. Also, the parameters that get passed to the method and the block (if one was given) are available as well. Note that the parameters are passed as individual parameters to method_missing, so the usual convention is use the splat operator to collect them all into an array:

def method_missing name, *args, &block


So, since we can get the name of the method that was attempted, we can parse that name and do something intelligent with it. For example, if the user calls something like this:





So, let’s get to it; scrap those earlier methods and replace it this this:

def method_missing name, *args, &block
  tuts = @tutorials.dup
  name = name.to_s.downcase
  if (md = /^get_tuts_(by_|about_)(\w*?)((_by_|_about_)(\w*))?$/.match name)
    if md[1] == 'by_'! { |tut| tut[:author].downcase == md[2].gsub("_", " ") }! { |tut| tut[:tags].include? md[5].gsub("_", " ")      } if md[4] == '_about_'
    elsif md[1] == 'about_'! { |tut| tut[:tags].include? md[2].gsub("_", " ")      }! { |tut| tut[:author].downcase == md[5].gsub("_", " ") } if md[4] == '_by_'
    tuts = "This object doesn't support the object '#{name}'"

Don’t get worried, we’ll walk through all this now. We start by duplicating the @tutorials array; every Ruby object has a dup method that copies it; if we didn’t do this—and just said tuts = @tutorial—we would be working with the original array, which we don’t want to do; we want to preserve that array as it is. Then, we’ll filter out the tutorial hashes we don’t want.

We also have to get the name of the method; since it’s passed to method_missing as a symbol, we convert it to a string with to_s and then make sure it’s in lowercase with downcase.

Now, we have to check to see that the method matches the format we want; after all, it’s possible that someone could pass something else to the method. So, let’s parse that method name. If it matches, we’ll work out magic; otherwise, we’re return a default error message:

  if (md = /^get_tuts_(by_|about_)(\w*?)((_by_|_about_)(\w*))?$/.match name)
    tuts = "This object doesn't support the method '#{name}'"

That looks like a rather daunting, but you should understand it: basically, we’re looking for “get_tuts_” followed by “by_” or “about_”; then, we have an author’s name or a tag, followed by “_by_” or “_about_” and an author or tag. If that matches, we store the MatchData object in md; otherwise, we’ll get nil back; in that case, we’ll set tuts to the error message. We do this so that either way, we can return tuts.

So the regular expression matches, we’ll get a MatchData object. If the method name used was get_tuts_by_andrew_burgess_about_html, these are the indices that you have:

0. get_tuts_by_andrew_burgess_about_html
1. by_
2. andrew_burgess
3. _about_html
4. _about_
5. html

I’ll note that if one of the optional groups isn’t filled, its index has a value of nil.

So, the data we want is at indices 2 and 5; remember that we could get only a tag, only an author, or both (in either order). So, next we have to filter out the tuts that don’t match our criteria. We can do this with the array select method. It passes each item to a block, one by one. If the block returns true, the item is kept; if it returns false, the item is thrown out of the array. Let’s start with this:

if md[1] == 'by_'! { |tut| tut[:author].downcase == md[2].gsub("_", " ") }! { |tut| tut[:tags].include? md[5].gsub("_", " ")      } if md[4] == '_about_'

If md[1] is “by_”, we know the author came first. Therefore, inside the block of the first select call, we get the tut hash’s author name (downcase it) and compare it to md[2]. I’m using the global substitution method—gsub—to replace all the underscores with a single space. If the strings compare true, the item is kept; otherwise it’s not. In the second select call, we check for the tag (stored in md[5]) in the tut[:tags] array. The array include? method will return true if the item is in the array. Notice the modifier on the end of that line: we only do this if the fourth index is the string “_about_”.

Notice that we’re actually using the array select method: we’re using select! (with a bang / exclamation mark). This doesn’t return a new array with only the selected items; it works with the actual tuts array in memory.

Now that you understand that, you shouldn’t have a problem with the next lines:

elsif md[1] == 'about_'! { |tut| tut[:tags].include? md[2].gsub("_", " ")      }! { |tut| tut[:author].downcase == md[5].gsub("_", " ") } if md[4] == '_by_'

These lines do the same as above, but they’re for method names in the reverse situation: tag first, optional author second.

At the end of the method, we return tuts; this is either the filtered array, or the error message.

Now, let’s test this:

tuts = [
  { title: "How to transition an Image from B&W to Color with Canvas", author: "Jeffrey Way",       tags: ["javascript", "canvas"]  },
  { title: "Node.js Step by Step: Blogging Application",               author: "Christopher Roach", tags: ["javascript", "node"]        },
  { title: "The 30 CSS Selectors you Must Memorize",                   author: "Jeffrey Way",       tags: ["css", "selectors"]          },
  { title: "Responsive Web Design: A Visual Guide",                    author: "Andrew Gormley",    tags: ["html", "responsive design"] },
  { title: "Web Development from Scratch: Basic Layout",               author: "Jeffrey Way",       tags: ["html"]                                },
  { title: "Protect a CodeIgniter Application Against CSRF",           author: "Ian Murray",        tags: ["php", "codeigniter"]        },
  { title: "Manage Cron Jobs with PHP",                                author: "Nikola Malich",     tags: ["php", "cron jobs"]          }

nettuts = "Nettuts+", tuts

p nettuts.get_tuts_by_ian_murray
# [{:title=>"Protect a CodeIgniter Application Against CSRF", :author=>"Ian Murray", :tags=>["php", "codeigniter"]}]

p nettuts.get_tuts_about_html
# [{:title=>"Responsive Web Design: A Visual Guide", :author=>"Andrew Gormley", :tags=>["html", "responsive design"]}, {:title=>"Web Development from Scratch: Basic Layout", :author=>"Jeffrey Way", :tags=>["html"]}]

p nettuts.get_tuts_by_jeffrey_way_about_canvas
# [{:title=>"How to transition an Image from B&W to Color with Canvas", :author=>"Jeffrey Way", :tags=>["javascript", "canvas"]}]

p nettuts.get_tuts_about_php_by_nikola_malich
# [{:title=>"Manage Cron Jobs with PHP", :author=>"Nikola Malich", :tags=>["php", "cron jobs"]}]
p nettuts.submit_an_article
# This object doesn't support the method 'submit_an_article'"

I’m p-rinting out the results from these methods, so you can run this in a ruby file on the command line.

A Warning

I should mention that, while this is pretty cool, this isn’t necessarily the right use of method_missing. It’s there primarily as a safety to rescue you from errors. However, the convention isn’t bad: it’s widely used in the ActiveRecord classes that are a big part of Ruby on Rails.

A Bonus

You probably didn't know that there was a similar feature in JavaScript: it's the __noSuchMethod__ method on objects. As far as I know, it's only supported in FireFox, but it's an interesting idea. I've re-written the example above in JavaScript, and you can check it out at this JSBin.


That’s a wrap for today! I’ve got some interesting Ruby stuff up my sleeve, coming for you soon. Keep your eye on Nettuts+, and if you want something specific, let me know in the comments!

Related Posts
  • Code
    JavaScript & AJAX
    Testing in Node.jsNodejs testing chai retina preview
    A test driven development cycle simplifies the thought process of writing code, makes it easier, and quicker in the long run. But just writing tests is not enough by itself, knowing the kinds of tests to write and how to structure code to conform to this pattern is what it's all about. In this article we will take a look at building a small app in Node.js following a TDD pattern.Read More…
  • Code
    Kickstarting Your Rails EducationRails education retina preview
    It's been a long time since I last coded on the server-side. In fact, if you've read some of my tutorials, you may have noticed that I use ColdFusion as my application server. While ColdFusion still works great, it definitely doesn't have the panache and coolness of newer server-side technologies like Ruby on Rails. Wanting to be a bit more modern, I've decided to jump on the Ruby on Rails train. Both Ruby and the Rails framework are proven technologies that are stable and widely embraced so I think it's a great direction to head to in my server-side renaissance.Read More…
  • Code
    How to Accept Payments With StripeCode
    Processing credit cards is unfortunately far more difficult than we might hope, as developers. Given that it’s such a common task, is it really necessary that we jump through countless hoops (surrounded by fire, of course) for the sole purpose of processing a payment? Merchants? Gateways? SSL? Security? Very quickly, a seemingly simple operation can become an overwhelmingly confusing and, more importantly, dangerous task. Any time that you find yourself handling a user’s sensitive data, you better be on your toes. Read More…
  • Computer Skills
    40 Terminal Tips and Tricks You Never Thought You NeededIcon terminal 2x
    The Terminal is an exceptionally powerful tool, providing a command line interface to the underpinnings of OS X. It’s a topic we’ve covered at length before with our popular series Taming the Terminal. There’s a great deal that Terminal can do, from moving large numbers of files to changing preferences that we didn’t even know exist. To demonstrate just how versatile the Terminal is, I’ve rounded up 40 truly excellent Terminal tips and tricks that can come in very handy. Read More…
  • Code
    JavaScript & AJAX
    Better CoffeeScript Testing With MochaMocha coffeescript
    Recently, I’ve been doing a considerable amount of CoffeeScript work. One problem I ran into early-on was testing: I didn’t want to manually convert my CoffeeScript to JavaScript before I could test it. Instead, I wanted to test from CoffeeScript directly. How’d I end up doing it? Read on to find out!Read More…
  • Code
    JavaScript & AJAX
    Build Your First JavaScript LibraryYour first js library
    Ever marvelled at the magic of Mootools? Ever wondered how Dojo does it? Ever been curious about jQuery's gymnastics? In this tutorial, we’re going to sneak behind the scenes and try our hand at building a super-simple version of your favorite library.Read More…