Understanding Ruby and Rails: extract_options! from Arrays

This is article is part of my series Understanding Ruby and Rails. Please see the table of contents for the series to view the list of all posts.

How many times did you see a method call like the following one in your Rails application?

ruby my_method :arg1 my_method :arg1, :arg2, :argN my_method :arg1, :foo => true, :bar => 1

What makes my_method quite special is the ability to pass an arbitrary number of parameters (:arg1, :arg2…) followed by a list of keyword/value options.

This is made possible by a really helpful method provided by ActiveSupport called extract_options!. What this core extension does is to extract the options from the given set of arguments. When no options are available, the method returns a blank Hash.

Let me show you an example.

```ruby # Use args with the splat operation to allow # an unlimited number of parameters def my_method(*args) options = args.extract_options! puts “Arguments: #{args.inspect}” puts “Options: #{options.inspect}” end

my_method(1, 2) # Arguments: [1, 2] # Options: {}

my_method(1, 2, :a => :b) # Arguments: [1, 2] # Options: {:a=>:b} ```

extract_options! is largely used in every Rails project and you probably encountered it countless times. It powers the most part of Rails features you use every day including ActionController filters, ActiveRecord validations and finder methods.

```ruby # ActionController filters class MyController < ApplicationController before_filter :my_method, :if => :execute?, :only => %w(new) end

ActiveRecord validations and finders

class MyModel < ActiveRecord::Base validates_presence_of :field, :allow_blank => true

def self.my_find find(:all, :order => “id”, :limit => 10) end

end ```

extract_options! allows you to easily extract a list of options from an array of parameters, usually coming from a method invocation.

It isn’t a standard Ruby method but a Rails Core Extension and you need to require ActiveSupport in order to use it. Also, beware that this is a “bang” method, hence it definitely modifies the object it is called on.