Archive for the ‘Ruby’ Category

Memoize Techniques in Ruby and Rails

December 13, 2010

The headline isn’t a typo. If you haven’t heard of “memoizing”, it’s the act of caching the result of a method so that when you call the method in the future, it doesn’t have to do all the processing again. I’ll show you a few different ways to do this, along with the pros and cons of each.

Setup

Let’s setup a sample rails app to play with. I’m using Rails 3, and we’ll generate a simple model to work with:

memoize$ rails g model user first_name:string last_name:string
      invoke  active_record
      create    db/migrate/20101204003605_create_users.rb
      create    app/models/user.rb
      invoke    test_unit
      create      test/unit/user_test.rb
      create      test/fixtures/users.yml
memoize$ rake db:migrate
(in /Users/bellmyer/Desktop/bellmyer/blog/memoize)
==  CreateUsers: migrating ====================================================
-- create_table(:users)
   -> 0.0013s
==  CreateUsers: migrated (0.0014s) ===========================================

The Standard Idiom

You’ve probably seen the simplest form of memoization, whether you called it that or not. Our user model has a first_name and last_name. Let’s say we want to create a full_name method to combine the two:

class User < ActiveRecord::Base
  def full_name
    "#{first_name} #{last_name}"
  end
end

Let’s verify that it works as we expect:

memoize$ rails c
Loading development environment (Rails 3.0.1)
ruby-1.9.2-p0 > user = User.new :first_name => 'Bob', :last_name => 'Smith'
 => #<User id: nil, first_name: "Bob", last_name: "Smith", created_at: nil, updated_at: nil> 
ruby-1.9.2-p0 > user.full_name
 => "Bob Smith" 

Great! Now let’s try the simplest form of memoization:

class User < ActiveRecord::Base
  def full_name
    @full_name ||= "#{first_name} #{last_name}"
  end
end

The first time this method is called, @full_name doesn’t exist yet, so the code to the right of ||= is executed. The next time this method is called, the result of the method has already been stored in @full_name, so the method doesn’t need to recalculate it.

A Better Way

This quick-and-dirty method works well for a lot of stuff, but it doesn’t work in all cases. Let’s add another memoized method, and see if you can find the logical flaw:

  def has_full_name?
    @has_full_name ||= (!first_name.blank? && !last_name.blank?)
  end

This method checks to see if the user has both a first and last name. At first, it looks like it will work as well as our first method. But what if the result is false? @has_full_name will be set to false, which means the right side of the equation will be run from scratch each time.

Instead of checking if @has_full_name equates to true or false, we need to check if @has_full_name has been defined, like so:

  def has_full_name?
    return @has_full_name if defined?(@has_full_name)
    @has_full_name = (!first_name.blank? && !last_name.blank?)
  end

Now we’re returning @has_full_name if it exists, and evaluating it otherwise. No more true/false gotchas. This method is more reliable, but it’s not as short and sweet, I’ll admit.

Memoization with Method Arguments

What if we have a method with arguments? We usually want the same input to produce the same output. If we enter the same arguments to a method over and over, we’d expect the same return value. So why not take our memoization a step further, and add caching for methods with arguments?

  def formal_name(salutation='Mr.', suffix=nil)
    @formal_name ||= {}
    return @formal_name[[salutation, suffix]] if @formal_name.has_key?([salutation, suffix])

    @formal_name[[salutation, suffix]] = "#{salutation} #{full_name} #{suffix}"
  end

This is a bit more complicated. Since this methd can be called with different arguments, we initialize a hash to store our cached results. We use Hash’s has_key? method to check if we already have a value for the given arguments. Let’s try it out:

memoize$ rails c
user Loading development environment (Rails 3.0.1)
ruby-1.9.2-p0 > user = User.new :first_name => 'Bob', :last_name => 'Smith'
 => #<User id: nil, first_name: "Bob", last_name: "Smith", created_at: nil, updated_at: nil> 
ruby-1.9.2-p0 > user.formal_name('Mr.', 'Jr.')
 => "Mr. Bob Smith Jr." 
ruby-1.9.2-p0 > user.first_name = 'John'
 => "John" 
ruby-1.9.2-p0 > user.formal_name('Mr.', 'Jr.')
 => "Mr. Bob Smith Jr." 

You know the memoization is working, because I changed the first name, and formal_name still gave us the same answer.

Using Rails’ Memoize Module

Our “better way” is bulletproof, and we’ve even added the ability to handle method arguments. But it’s a lot of work to do this for every method, and it gunks up the readability of the method. We have to wade through the caching code to figure out what the method really does.

If you’re using Rails, 2.2 or later, you can take advantage if its Memoize module to clean this up.
Let’s add a method that uses it:

class User < ActiveRecord::Base
  extend ActiveSupport::Memoizable

  # other methods...
  
  def initials(middle_initial)
    first_name[0] + middle_initial + last_name[0]
  end
  memoize :initials
end

It’s that easy! The memoize method takes care of things for you, but you have to extend your class with the module for it to work. And unlike the other memoization strategies discussed, this uses ActiveSupport, so it’s Rails-specific.

The good news is that if you’re using Rails for your project, you can use Memoizable anywhere. Let’s add a non-activerecord class in our lib folder:

# lib/my_number.rb
class MyNumber
  extend ActiveSupport::Memoizable
  
  attr_accessor :x
  
  def initialize(x)
    @x = x
  end
  
  def plus(y)
    @x + y
  end
  memoize :plus
end

And here’s the proof that it works:

memoize$ rails c
require 'myLoading development environment (Rails 3.0.1)
ruby-1.9.2-p0 > require 'my_number'
 => ["MyNumber"] 
ruby-1.9.2-p0 > num = MyNumber.new(5)
 => #<MyNumber:0x00000104434bf8 @x=5> 
ruby-1.9.2-p0 > num.plus 2
 => 7 
ruby-1.9.2-p0 > num.x = 0
 => 0 
ruby-1.9.2-p0 > num.plus 2
 => 7 

This is a much better solution if you’re using Rails, and I highly recommend it. The less code you type by hand, the less chance of adding a bug somewhere.

Things You Should Know

First, as mentioned above, the Memoizable module is only available in ActiveSupport, part of Rails. But the previous examples are pure Ruby, and can be used in any Ruby project.

You don’t want to use memoization everywhere. Here are some situations where it’s not appropriate:

  • The method is simple, and memoizing it won’t save you much (there is some overhead involved).
  • The method’s output needs to change over the life of its object
  • The method is unlikely to be called again with the same parameters.
  • There are so many combinations of parameters that will be called, it will eat up too much memory to store all the results.

Ruby Enumerable Magic: Aggregates

December 10, 2010

  1. The Basics
  2. Unary Ampersand Operator
  3. Booleans
  4. Filters
  5. New Collections
  6. Aggregates
 

This final article in my series about the Enumerable module details the methods that don’t quite fit elsewhere, but deal with the collection as a whole. As such, they each return just one object, not an array.

inject

If you haven’t used this method before, it’s loads of fun. It’s a cumulative method that uses each item in the collection to form a “final answer”. The classic example is finding the sum of the numbers in an array:

irb(main):001:0> [1, 2, 3].inject{|sum, num| sum += num}
=> 6

Another use might be finding the initials in a name:

irb(main):008:0> ['Jaime', 'Lee', 'Bellmyer'].inject(''){|initials, name| initials += name[0,1]}
=> "JLB"

In this example, I had to pass the starting string (”, or blank) to inject. Otherwise, it takes the first element as a whole, and starts adding onto it. I don’t like this behavior, and I suspect it works this way because inject assumes you’re trying to sum elements in some way. You also need to pass an initial value to inject when you want the result to be a different class than the inputs:

irb(main):009:0> [1, 2, 3].inject(0.0){|sum, i| sum += i.to_f}
=> 6.0

min and max

These methods behave largely like you’d expect. The items in the collection have to have the <=> method defined, just like the sorting methods, since finding the min and max requires sorting. So strings and numbers behave like you’d expect:

irb(main):010:0> ['joshua', 'gabriel', 'jacob'].min
=> "gabriel"
irb(main):011:0> ['joshua', 'gabriel', 'jacob'].max
=> "joshua"
irb(main):012:0> [1,2,3].min
=> 1
irb(main):013:0> [1,2,3].max
=> 3

And you can also pass your own custom sorting block, like you can with the sort method:

irb(main):014:0> ['joshua', 'gabriel', 'jacob'].min{|a,b| a.reverse <=> b.reverse}
=> "joshua"
irb(main):015:0> ['joshua', 'gabriel', 'jacob'].max{|a,b| a.reverse <=> b.reverse}
=> "gabriel"
irb(main):016:0> [1,2,3].min{|a,b| a*(-1) <=> b*(-1)}
=> 3
irb(main):017:0> [1,2,3].max{|a,b| a*(-1) <=> b*(-1)}
=> 1

In conclusion

What a long journey it has been. I’d like to thank myself for completing my longest series of articles, in the most timely manner yet. And I’d like to thank you if you suffered through all of it for the sake of knowledge. Please feel free to ask any questions you might have, and I’ll do my best to answer them promptly.

And thus concludes our two-week look at the Enumerable module.

Ruby String Interpolation

December 8, 2010

String interpolation is the process of converting placeholders inside a string to the values they represent, in order to produce a dynamic string. You probably use it all the time without realizing just how cool it works under the hood, and how you can leverage this power in your own classes.

I came from a Perl environment, where variables look like $variable, and so string interpolation was pretty simple:

$person = 'World'
print "Hello, $person!"    # prints "Hello, World!"

Perl just recognized any alphanumeric word starting with a dollar sign as a variable, and replaced it inline. Ruby variables don’t start with a dollar sign though, so it’s a little more typing. Here’s how you include variables:

person = 'World'
puts "Hello, #{person}!"    # prints "Hello, World!"

Ruby uses the idiom #{} to denote something that needs to be interpreted. But this extra typing comes with a huge benefit. You can include more than just strings, you can include entire expressions! Say our variable isn’t already capitalized, and we want to do that inline:

person = 'world'
puts "Hello, #{person.capitalize}!"  # prints "Hello, World!"

Ruby will run the code inside the braces, and display that. But it gets even better: Ruby will interpret any type of expression, and convert it to a string for you:

  puts "4 = #{4}"    # prints "4 = 4"
  puts "2 + 2 = #{2+2}"  # prints "2 + 2 = 4"

Even if the code inside the braces isn’t a string, Ruby will convert inline. How does it do this? It calls the to_s method on the result of the expression. The expression 2 + 2 equates to 4, which is a Fixnum object. This object, like every other in Ruby, has a to_s method.

Another big benefit of this is that you can decide how your own objects will be displayed in strings. Let’s say you have a user class:

class User
  attr_accessor :first_name, :last_name

  def initialize first, last
    self.first_name = first
    self.last_name = last
  end

  def to_s
    "#{first_name} #{last_name}"
  end
end

We’ve just told Ruby that when our user object is converted to a string, we want it to show the full name (first and last). Let’s try it out:

user = User.new 'Jaime', 'Bellmyer'
puts "Hello, #{user}!"    # prints "Hello, Jaime Bellmyer!"

This is one of many instances where knowing how ruby handles things under the hood can allow you create powerful code of your own. Enjoy!

Ruby Enumerable Magic: New Collections

December 8, 2010

  1. The Basics
  2. Unary Ampersand Operator
  3. Booleans
  4. Filters
  5. New Collections
  6. Aggregates
 

The Enumerable module offers several methods to create a new collection out of an existing one, by applying code to each item in the original collection.

map

This is the most common and straightforward method in the Enumerable module. It takes the original collection, applies the given block to each item within, and returns an array of the results:

irb(main):001:0> ['joshua', 'gabriel', 'jacob'].map{|name| name.capitalize}
=> ["Joshua", "Gabriel", "Jacob"]
irb(main):002:0> ['joshua', 'gabriel', 'jacob'].map(&:capitalize)
=> ["Joshua", "Gabriel", "Jacob"]

As with all Ruby methods that require a block, we can pass a block itself, or use the unary ampersand operator to pass a symbol that will be converted to a block and run on the object.

sort

This method will return the same, unaltered items in the collection, but in a sorted order. It does this using each item’s <=> method. Objects like strings choose to be sorted alphabetically. Number classes choose to sort numerically. The important thing is that the items in the collection must have this method defined.

Now for an example:

irb(main):003:0> ['joshua', 'gabriel', 'jacob'].sort
=> ["gabriel", "jacob", "joshua"]
irb(main):004:0> [3, 1, 5].sort
=> [1, 3, 5]

You can also pass a block that will be used to sort items, if the default sort is not good enough. For instance, we could choose to sort strings alphabetically, but starting from last letter to first:

irb(main):005:0> ['joshua', 'gabriel', 'jacob'].sort{|a,b| a.reverse <=> b.reverse}
=> ["joshua", "jacob", "gabriel"]

sort_by

A shorter way to sort based on the reversed version of strings like we did above, is to use the sort_by method, and passing either a block or using the unary ampersand operator to pass a symbol:

irb(main):007:0> ['joshua', 'gabriel', 'jacob'].sort_by{|name| name.reverse}=> ["joshua", "jacob", "gabriel"]
irb(main):008:0> ['joshua', 'gabriel', 'jacob'].sort_by(&:reverse)
=> ["joshua", "jacob", "gabriel"]

This is like calling map before calling sort. It will sort the results of the map method, not the collection items themselves.

zip

Honestly, I haven’t found a good use case for this method, but I also didn’t know it existed until I did the research for this article. It has nothing to do with compression – a better name for it might have been “zipper”. Have you ever noticed on the highway when two lanes merge, a zipper effect is created? People instinctively take turns getting in line, much like the teeth of a zipper.

This method works in a similar fashion:

irb(main):010:0> [1, 2, 3].zip([4, 5, 6])
=> [[1, 4], [2, 5], [3, 6]]
irb(main):011:0> [1, 2, 3].zip([4, 5, 6], [7, 8, 9])
=> [[1, 4, 7], [2, 5, 8], [3, 6, 9]]

It will take the original collection, and merge in the given array or arrays, as shown above. While I don’t yet know a great use case, I’ll keep my eyes peeled now that I understand how it works.

Dynamic Form Elements in Ruby on Rails

December 7, 2010

If I showed you a snippet from a form view, you’d probably recognize all the parts:

<div class="field">
  <%= f.label :first_name %><br />
  <%= f.text_field :first_name %>
</div>
<div class="field">
  <%= f.label :last_name %><br />
  <%= f.text_field :last_name %>
</div>
<div class="actions">
  <%= f.submit %>
</div>

You’d probably guess that the User model has at least two attributes: first_name and last_name. You’d normally be right, but that doesn’t have to be the case. What if I want the database to store first and last names separately, but I want the form to let them type their full name, and I’d split it up behind the scenes? Something like this:

<div class="field">
  <%= f.label :full_name, 'Name' %><br />
  <%= f.text_field :full_name %>
</div>

It’s easy to do, just by adding accessor methods to our model, like so:

class User < ActiveRecord::Base
  def full_name
    "#{first_name} #{last_name}"
  end

  def full_name= name
    self.first_name, self.last_name = name.split(/\s+/, 2)
  end
end

In the example above, we have a getter that spits out the first and last name put together. We also have a setter, that tries to intelligently split a full name into its parts.

Now that there is a full_name and full_name= method in our model, we can use it in our forms like any other attribute. This is because the attributes themselves are just sets of accessor methods that are added to your model by ActiveRecord, built using the database schema for that model’s table.

In other words, if your model’s table has a first_name field, ActiveRecord will automatically create the first_name and first_name= methods for you. It’s these methods (called accessors) that Rails form builders look for, whether they’re attributes stored in the database or not.

Ruby Enumerable Magic: Filters

December 6, 2010

  1. The Basics
  2. Unary Ampersand Operator
  3. Booleans
  4. Filters
  5. New Collections
  6. Aggregates
 

A powerful part of the Enumerable module is the set of methods that help you filter a larger collection down to a smaller one, containing just the items you need. There are several methods to help.

entries (or to_a)

This is the most permissive of the Enumerable filter methods – it doesn’t filter out anything. In fact, if you use this on an array you won’t see any difference at all. entries returns the list of items in the collection. For an array, the array itself will be returned. This makes sense, when you see that this method is aliased as to_a.

But more complex collections like our Team class will provide a better example. Here’s the class, in case you missed it from previous posts:

class Team
  include Enumerable
  
  attr_accessor :members
  
  def initialize
    @members = []
  end
  
  def each &block
    @members.each{|member| block.call(member)}
  end
end

Let’s use entries:

irb(main):001:0> require 'team.rb'
=> true
irb(main):002:0> team = Team.new
=> #<Team:0x100391088 @members=[]>
irb(main):003:0> team.members = ['joshua', 'gabriel', 'jacob']
=> ["joshua", "gabriel", "jacob"]
irb(main):004:0> team
=> #<Team:0x100391088 @members=["joshua", "gabriel", "jacob"]>
irb(main):005:0> team.entries
=> ["joshua", "gabriel", "jacob"]

You can see that team is a non-array collection, but calling entries returns the members list. To be honest, this isn’t immensely useful – but it’s good to know that it exists, and how it works.

select (or find_all)

In contrast to entries, select is arguably the most used enumerable filter. It returns a list of all the collection items that pass the test that you pass in as a block. For example:

irb(main):006:0> team.select{|member| member =~ /^j/}
=> ["joshua", "jacob"]

Here we want to filter the collection to just those items that start with the letter “j”. As with all Ruby methods that expect a block, we can use the unary ampersand operator to make our code shorter and sweeter:

irb(main):007:0> team.members[1].freeze
=> "gabriel"
irb(main):008:0> team.select(&:frozen?)
=> ["gabriel"]

In the example above, we “froze” the second member in the collection, “gabriel”. Then we called select on the collection, asking for just the frozen members.

reject

This is the opposite of select. It will only return items in the collection that *don’t* pass the test we give it. Let’s do the opposite of our last two tests:

irb(main):009:0> team.reject{|member| member =~ /^j/}
=> ["gabriel"]
irb(main):010:0> team.reject(&:frozen?)
=> ["joshua", "jacob"]

partition

This little method probably deserves a lot more use and recognition than it gets. You might say it’s the Bruce Campbell of enumerable methods. It’s like calling select AND reject on a collection. it gives you both lists back – the passers, and the failures:

irb(main):011:0> frozen, not_frozen = team.partition(&:frozen?)
=> [["gabriel"], ["joshua", "jacob"]]
irb(main):012:0> frozen
=> ["gabriel"]
irb(main):013:0> not_frozen
=> ["joshua", "jacob"]

grep

In our previous examples, we’ve used regular expressions in some of our filter methods. To be honest, I do this a lot. I didn’t realize that Enumerable provided a special method just for this use case until I researched this article. It works like select, except it only takes a regular expression pattern, no need to pass it a block. That means this snippet:

irb(main):014:0> team.select{|member| member =~ /^j/}
=> ["joshua", "jacob"]

Can be rewritten like this:

irb(main):015:0> team.grep(/^j/)
=> ["joshua", "jacob"]

If you like passing blocks to methods (and who doesn’t??) then you’re in luck, because you can still do that with grep. If you pass a block, each collection item that matches the regular expression will be run through the block, and the results will be gathered up into the return array for you. Like this:

irb(main):016:0> team.grep(/^j/){|member| member.capitalize}
=> ["Joshua", "Jacob"]

grep found our matches, passed each one through capitalize, and gave us a list of the results.

detect (or find)

detect works a lot like select, except it stops looking as soon as it finds the first match. Unlike the other methods, it doesn’t return an array. It returns just the single item:

irb(main):017:0> team.detect{|member| member =~ /^j/}
=> "joshua"

By default, detect will return nil if no match is found. But you can pass a block, which it will run and return, if no match is found:

irb(main):018:0> team.detect(lambda{'turtles'}){|member| member =~ /^t/}
=> "turtles"

An alias for this method is find, which you’ll obviously want to avoid if you’re in a Rails application, since ActiveRecord has its own find method, and you don’t want to make your code harder to read.

Summary

Don’t be a fool, like I was, and wait until you write your own article about enumerables to brush up on all the filter methods. I remember the first time I changed the brakes on my own car. One nut would not come loose, and I was even using vise grips on it. After a few hours, I called a friend who brought over a tool that actually tightens the more you crank it (unlike vise grips where you determine the pressure beforehand) and it was off in under a minute. The first step in knowing the right tool for the job is knowing what tools you have at your disposal.

Ruby Enumerable Magic: Booleans

December 3, 2010

  1. The Basics
  2. Unary Ampersand Operator
  3. Booleans
  4. Filters
  5. New Collections
  6. Aggregates
 

The most basic Enumerable methods are those that give you a simple yes/no answer. There are three of these boolean methods: all?, any?, and include?. Each gives you quick info about the collection you’re working on.

We’ll start out our Team class from previous articles:

class Team
  include Enumerable
  
  attr_accessor :members
  
  def initialize
    @members = []
  end
  
  def each &block
    @members.each{|member| block.call(member)}
  end
end

all?

This method tells you if *every* item in your collection matches the criteria you give it. Let’s test it out:

irb(main):001:0> require 'team.rb'
=> true
irb(main):002:0> team = Team.new
=> #<Team:0x100391088 @members=[]>
irb(main):003:0> team.members = ['joshua', 'gabriel', 'jacob']
=> ["joshua", "gabriel", "jacob"]
irb(main):004:0> team.all?{|member| member.length > 4}
=> true
irb(main):005:0> team.all?{|member| member.length > 5}
=> false

Here we’re checking to see if all members (which are just strings containing their names) meet a certain length. All of the names have more than four characters, so all? returns true. However, only two of the three names contain more than five letters, so all? returns false in the second test.

Whatever block you pass to all? will be evaluated for each item in the collection (members in this case) and the method will only return true if all items return true.

any?

all? is a little strict, like an uptight parent demanding “all” your dirty clothes be put in the hamper. Wouldn’t it be nice to get partial credit? any? promotes permissive searches and parenting by only requiring that one item in the collection meet the given criteria. As long as any item evaluates to true (using the block you pass in), the whole collection gets the thumbs up.

irb(main):001:0> require 'team.rb'
=> true
irb(main):002:0> team = Team.new
=> #<Team:0x100391088 @members=[]>
irb(main):003:0> team.members = ['joshua', 'gabriel', 'jacob']
=> ["joshua", "gabriel", "jacob"]
irb(main):004:0> team.any?{|member| member == 'joshua'}
=> true
irb(main):005:0> team.any?{|member| member == 'javier'}
=> false

The example above is like a party. When you open the door and see three people standing there, you really only need to know *one* of them, and they’re all welcome. In the first example, if anybody in the team is named “joshua”, the whole collection is green-lighted for beer and awkward dancing. In the second example, if you don’t have a “javier” on your team, you’ll have to stay in the hallway, drinking the beer you brought yourself, and standing awkwardly.

include?

This is my favorite boolean enumerable method, simply because I always forget how to spell it. I always want to type includes? when the collection name is singular (like “team”). But it makes sense when the collection is plural, as in members.include?.

Our examples above can be shortened to use the include? syntax:

irb(main):001:0> require 'team.rb'
=> true
irb(main):002:0> team = Team.new
=> #<Team:0x100391088 @members=[]>
irb(main):003:0> team.members = ['joshua', 'gabriel', 'jacob']
=> ["joshua", "gabriel", "jacob"]
irb(main):004:0> team.include?('joshua')
=> true
irb(main):005:0> team.include?('javier')
=> false

First, note that include? doesn’t take a block – it takes one parameter, an item. This method will check the whole collection to see if that item is in there, and return true or false.

The Enumerable module contains a handful of handy boolean methods, but the real power comes in filtering collections down to the desired items. As luck would have it, that’s the topic of my next article.

Routing in Ruby on Rails 3

December 2, 2010

Be thee warned, this is a *long* article. However, it covers a lot of ground, is written in plain english, and comes with tons of code samples to make the subject matter as easy to digest as possible.

Routing has changed in Rails 3. It’s very different from 2.x, but it’s not actually difficult. This is one of those things where new users are almost better off, because they’re learning the simple way right off the bat, with no baggage. Whether you’re new to all of Rails or just Rails 3, this will get you up and running.

Static-y routes

Starting off with a fresh rails app, let’s generate our main static controller:

rails3_routing$ rails g controller home index about
      create  app/controllers/home_controller.rb
       route  get "home/about"
       route  get "home/index"
      invoke  erb
      create    app/views/home
      create    app/views/home/index.html.erb
      create    app/views/home/about.html.erb
      invoke  test_unit
      create    test/functional/home_controller_test.rb
      invoke  helper
      create    app/helpers/home_helper.rb
      invoke    test_unit
      create      test/unit/helpers/home_helper_test.rb

We can clean up our routes file so it looks something like this:

Rails3Routing::Application.routes.draw do
  get "home/index"
  get "home/about"

  root :to => "home#index"
end

The controller generator created the two static routes for us, and I made home/index the root (default) route for the application. Now I need to get rid of the default index file in the public directory:

rails3_routing$ ls public
404.html	500.html	images		javascripts	stylesheets
422.html	favicon.ico	index.html	robots.txt
rails3_routing$ rm public/index.html
rails3_routing$ ls public
404.html	500.html	images		robots.txt
422.html	favicon.ico	javascripts	stylesheets

If we don’t remove this, the app will show the public/index.html file as the home page. So far so good! If you fire up the server, you’ll see our home/index action is being called as our home page.

RESTful Routes

Let’s use the example of a blog application, and create the Post model, views, and controller to look at RESTful routing in Rails 3. We’ll use the scaffold generator to create the entire MVC (Model-View-Controller) stack in one shot:

rails3_routing$ rails g scaffold post title:string content:text
      invoke  active_record
      create    db/migrate/20101202051750_create_posts.rb
      create    app/models/post.rb
      invoke    test_unit
      create      test/unit/post_test.rb
      create      test/fixtures/posts.yml
       route  resources :posts
      invoke  scaffold_controller
      create    app/controllers/posts_controller.rb
      invoke    erb
      create      app/views/posts
      create      app/views/posts/index.html.erb
      create      app/views/posts/edit.html.erb
      create      app/views/posts/show.html.erb
      create      app/views/posts/new.html.erb
      create      app/views/posts/_form.html.erb
      invoke    test_unit
      create      test/functional/posts_controller_test.rb
      invoke    helper
      create      app/helpers/posts_helper.rb
      invoke      test_unit
      create        test/unit/helpers/posts_helper_test.rb
      invoke  stylesheets
      create    public/stylesheets/scaffold.css

Looking at our routes.rb file, you can see we now have our first RESTful route, added automatically by Rails:

Rails3Routing::Application.routes.draw do
  resources :posts

  get "home/index"
  get "home/about"

  root :to => "home#index"
end

This doesn’t look like much – it only added a line to our routes file – but it packs a punch. For starters, it’s defining the seven basic RESTful routes:

  • GET index
  • GET show
  • GET new
  • POST create
  • GET edit
  • PUT update
  • DELETE destroy

These are the seven routes needed to list, view, add, update, and remove posts in our application. But what if we want to add custom routes to this controller? Maybe we want a couple actions called recent that shows only the latest 5 posts, and popular that shows the top 5 popular posts. Let’s also add an action called publish that will activate a post once it’s ready, so people can see it. Let’s add these to our routes:

  resources :posts do
    get 'recent', :on => :collection
    get 'popular', :on => :collection
    
    put 'publish', :on => :member
  end

Both recent and popular use http GET requests, because we’re not changing any data on the server. The publish action uses the http PUT request, to denote a route that does changes records on the server.

The publish action is a member action, meaning when we call this action, the route will have to contain the id of the record we want to work with, like this: “/posts/1/publish”. The other two actions are collection-oriented, meaning they work with the collection as a whole and we don’t need to pass a specific id to them. The recent route would look like “/posts/recent”.

When you start adding routes, the notation above may get tedious. Luckily, there’s a shortcut:

  resources :posts do
    collection do
      get 'recent'
      get 'popular'
    end
    
    member do
      put 'publish'
    end
  end

This is the preferred way to notate custom routes, whether you have many or just a couple. It’s easier to read, and easier to update with more routes in the future.

Nested Routes

Now let’s say we want to add comments to our application. Obviously every comment will be attached to a specific post, and we’d like the routes to reflect this. It’s not absolutely necessary, but it does add much needed structure in these trying and uncertain times. Let’s generate our comments:

rails3_routing$ rails g scaffold comment title:string content:text post_id:integer
      invoke  active_record
      create    db/migrate/20101202054608_create_comments.rb
      create    app/models/comment.rb
      invoke    test_unit
      create      test/unit/comment_test.rb
      create      test/fixtures/comments.yml
       route  resources :comments
      invoke  scaffold_controller
      create    app/controllers/comments_controller.rb
      invoke    erb
      create      app/views/comments
      create      app/views/comments/index.html.erb
      create      app/views/comments/edit.html.erb
      create      app/views/comments/show.html.erb
      create      app/views/comments/new.html.erb
      create      app/views/comments/_form.html.erb
      invoke    test_unit
      create      test/functional/comments_controller_test.rb
      invoke    helper
      create      app/helpers/comments_helper.rb
      invoke      test_unit
      create        test/unit/helpers/comments_helper_test.rb
      invoke  stylesheets
   identical    public/stylesheets/scaffold.css

Now our routing file will have our comments routes, but they’re not nested inside our posts routes. Let’s fix that:

  resources :posts do
    resources :comments

    collection do
      get 'recent'
      get 'popular'
    end
    
    member do
      put 'publish'
    end
  end

Easy! We just moved the resource line into our posts block. In order to complete the process, I’ve added the necessary relationships in the models, before filter in the comments controller (to lookup the parent post) and updated the comments controller to perform all comment lookups from the perspective of the parent post. Feel free to view the source code for this article (link at the top of the page) to see how I did this.

Now if you’re editing a comment with id 100 that belongs to post 20, the route will look like: “/posts/20/comments/100/edit”.

Namespaced Routes

After a while, you might realize that your posts and comments need to be treated differently depending on the context. One way to do this is with namespacing. For example, you might want to create an admin section of the site where posts are shown with more options (re-ordering, editing, etc). While I won’t get into the permissions issues in this article, this is easy to do from a routing perspective.

First, we’ll create the namespaced controller:

rails3_routing$ rails g controller admin/posts index show new create edit update destroy
      create  app/controllers/admin/posts_controller.rb
       route  get "posts/destroy"
       route  get "posts/update"
       route  get "posts/edit"
       route  get "posts/create"
       route  get "posts/new"
       route  get "posts/show"
       route  get "posts/index"
      invoke  erb
      create    app/views/admin/posts
      create    app/views/admin/posts/index.html.erb
      create    app/views/admin/posts/show.html.erb
      create    app/views/admin/posts/new.html.erb
      create    app/views/admin/posts/create.html.erb
      create    app/views/admin/posts/edit.html.erb
      create    app/views/admin/posts/update.html.erb
      create    app/views/admin/posts/destroy.html.erb
      invoke  test_unit
      create    test/functional/admin/posts_controller_test.rb
      invoke  helper
      create    app/helpers/admin/posts_helper.rb
      invoke    test_unit
      create      test/unit/helpers/admin/posts_helper_test.rb

As you can see, calling the controller “admin/posts” caused all the newly created files to be put in their own admin directory. If we look in the routes file, we’ll see this ugliness:

  get "posts/index"

  get "posts/show"

  get "posts/new"

  get "posts/create"

  get "posts/edit"

  get "posts/update"

  get "posts/destroy"

The controller generator doesn’t know that we want RESTful, namespaced routes, so we’ll drop all those lines in favor of this:

  namespace :admin do
    resources :posts
  end

Note that we’re adding posts resources again, but this time they’re namespaced. They won’t interfere with our regular posts routes, because these routes will be prefixed with “/admin”. So editing the post with id “100″ in the admin section will have a route like this: “/admin/posts/100/edit”.

Things You Should Know

While our initial routes file is pretty simple and straightforward, it would quickly grow if this were a real app. How does the Rails 3 routing engine choose from conflicting or overlapping routes? It does this the same way Rails 2.x does – it works top to bottom. It does not try to find the *best* match (the way a google search might) – instead, it starts at the top of the routes file and stops when it finds the first acceptable match. Therefore, default routes should be pushed to the bottom.

While we’re on the subject, don’t use default routes. Named routes form a much more secure and stable application. There shouldn’t be routes you’re NOT expecting. One exception can be short urls. If you want members to have a short url the way Twitter does (http://twitter.com/kconrails for instance) then you’ll need a default route, placed at the bottom of the routes file, to be tried after all other routes have been checked. If you had a members controller, and the member name should route to the show action, the route might look like this:

match ':member' => 'members#show', :as => :shorturl

Finally, when in doubt, check your existing routes with this rake task:

rails3_routing$ rake routes
(in /Users/bellmyer/Desktop/bellmyer/blog/rails3_routing)
      admin_posts GET    /admin/posts(.:format)                      {:action=>"index", :controller=>"admin/posts"}
      admin_posts POST   /admin/posts(.:format)                      {:action=>"create", :controller=>"admin/posts"}
   new_admin_post GET    /admin/posts/new(.:format)                  {:action=>"new", :controller=>"admin/posts"}
  edit_admin_post GET    /admin/posts/:id/edit(.:format)             {:action=>"edit", :controller=>"admin/posts"}
       admin_post GET    /admin/posts/:id(.:format)                  {:action=>"show", :controller=>"admin/posts"}
       admin_post PUT    /admin/posts/:id(.:format)                  {:action=>"update", :controller=>"admin/posts"}
       admin_post DELETE /admin/posts/:id(.:format)                  {:action=>"destroy", :controller=>"admin/posts"}
    post_comments GET    /posts/:post_id/comments(.:format)          {:action=>"index", :controller=>"comments"}
    post_comments POST   /posts/:post_id/comments(.:format)          {:action=>"create", :controller=>"comments"}
 new_post_comment GET    /posts/:post_id/comments/new(.:format)      {:action=>"new", :controller=>"comments"}
edit_post_comment GET    /posts/:post_id/comments/:id/edit(.:format) {:action=>"edit", :controller=>"comments"}
     post_comment GET    /posts/:post_id/comments/:id(.:format)      {:action=>"show", :controller=>"comments"}
     post_comment PUT    /posts/:post_id/comments/:id(.:format)      {:action=>"update", :controller=>"comments"}
     post_comment DELETE /posts/:post_id/comments/:id(.:format)      {:action=>"destroy", :controller=>"comments"}
     recent_posts GET    /posts/recent(.:format)                     {:action=>"recent", :controller=>"posts"}
    popular_posts GET    /posts/popular(.:format)                    {:action=>"popular", :controller=>"posts"}
     publish_post PUT    /posts/:id/publish(.:format)                {:action=>"publish", :controller=>"posts"}
            posts GET    /posts(.:format)                            {:action=>"index", :controller=>"posts"}
            posts POST   /posts(.:format)                            {:action=>"create", :controller=>"posts"}
         new_post GET    /posts/new(.:format)                        {:action=>"new", :controller=>"posts"}
        edit_post GET    /posts/:id/edit(.:format)                   {:action=>"edit", :controller=>"posts"}
             post GET    /posts/:id(.:format)                        {:action=>"show", :controller=>"posts"}
             post PUT    /posts/:id(.:format)                        {:action=>"update", :controller=>"posts"}
             post DELETE /posts/:id(.:format)                        {:action=>"destroy", :controller=>"posts"}
       home_index GET    /home/index(.:format)                       {:controller=>"home", :action=>"index"}
       home_about GET    /home/about(.:format)                       {:controller=>"home", :action=>"about"}
             root        /(.:format)                                 {:controller=>"home", :action=>"index"}

It will give you a list of all available routes that have been setup in your application. It also gives you the route names. The first word of each line is the route name. The first named route in our example is “admin_posts”. You can append “_url” or “_path” in views and controllers to get either that action’s url with or without the hostname, respectively.

Also note that in the routes listed above, any symbols that are NOT in parentheses are required. For example, on line 10 above, post_comments_path would require post_id to be passed in. You can do this with either the id, or the object itself. For example

post_comments_path(@post)
post_comments_path(@post.id)

This is a lot to play with, which is why I like including code samples with articles like this. Download (link at the top of the page) and play around with the routes until you're comfortable. After and hour or so, you won't need to lookup the Rails specs every time you want to make a routing change.

Ruby Enumerable Magic: Unary Ampersand Operator

December 1, 2010

  1. The Basics
  2. Unary Ampersand Operator
  3. Booleans
  4. Filters
  5. New Collections
  6. Aggregates
 

You’ve probably seen this example in my previous post, or in other Ruby code:

irb(main):001:0> ['a', 'b', 'c'].map(&:capitalize)
=> ["A", "B", "C"]

This is a cool trick, which equates to:

['a', 'b', 'c'].map{|letter| letter.capitalize}

Most Ruby developers have seen this idiom, and even used it, but you may not know how it works. This is *not* strictly a piece of Enumerable magic, even though this is probably where you see it used most often. We can all harness this power, but much like the Force it can be used for good or evil.

There are really two pieces of magic used together to make this possible. The first is the unary ampersand operator. Contrary to what you might think, there is no “&:” operator in Ruby. What you’re seeing in my first example above is actually “&” and “:capitalize”, pushed together. That first character is the unary ampersand. The second piece is a Ruby symbol that is being passed to the operator.

When Ruby sees the unary ampersand on the last argument of a method, it tries to convert it to a proc (an executable block of code), and run it. It does this by calling to_proc on the object. This is where the second piece of magic comes in. Rails 1.1 added a to_proc method to the Symbol class, so that you could pass a symbol to the unary ampersand (ie, &:capitalize) and it would convert it for you. Ruby 1.8.7 rolled this change into Ruby itself, so you can use it outside of Rails.

Digging into “The Why” can be fun, but what I really wanted to know is how I could harness this Ruby voodoo (or, if you will, “rooboo”) for my own selfish gain. That was, by far, the hardest part of putting together this guide. The good news is, once I figured it out, it’s easy to pass on.

Let’s use the example of a Translator class with one public method: speak. This class has a method for each of the languages it knows, and a catch-all method (Ruby’s method_missing) for languages it doesn’t understand:

class Translator
  def speak &language
    language.call(self)
  end
  
  protected
  
  def french
    'bon jour'
  end
  
  def spanish
    'hola'
  end
  
  def turkey
    'gobble'
  end
  
  def method_missing *args
    'awkward silence'
  end
end

This is awesome! Let’s play with it in irb:

irb(main):001:0> require 'translator.rb'
=> true
irb(main):002:0> translator = Translator.new
=> #<Translator:0x10038ff08>
irb(main):003:0> translator.speak(&:spanish)
=> "hola"
irb(main):004:0> translator.speak(&:turkey)
=> "gobble"
irb(main):005:0> translator.speak(&:italian)
=> "awkward silence"

The key to this magic is in the speak method:

  def speak &language
    language.call(self)
  end

There’s a lot going on here. When Ruby converts :turkey into a proc from a symbol, it makes the assumption that a receiver will be passed into the proc, and the proc will be called *on* that receiver. In this case, we pass self into the proc above. This is like calling self.turkey. Gobble.

Is this a super useful example? Maybe not. But it lets you play with the smallest possible working example, and get comfortable. If you have any questions, please leave a comment below.

Ruby Enumerable Magic: The Basics

November 30, 2010

  1. The Basics
  2. Unary Ampersand Operator
  3. Booleans
  4. Filters
  5. New Collections
  6. Aggregates
 

You’re probably familiar with Ruby’s Enumerable module, even if you don’t know it by that name. It adds neat methods to arrays, like map, inject, select, and so on. You might have thought (like I did for a long time) that these methods were *array* methods, but they’re not.

Ruby’s arrays use Enumerable, and you can as well, in any class you want. Of course, the class should represent a collection of things, or all the iterative methods in Enumerable wouldn’t make much sense. Let’s say we have a Team class, that manages a group of members:

class Team
  include Enumerable
  
  attr_accessor :members
  
  def initialize
    @members = []
  end
  
  def each &block
    @members.each{|member| block.call(member)}
  end
end

Enumerable requires that your class contain an each method that serves up the items in the collection. All the other Enumerable methods rely on this. Now we can use the map method, for instance:

irb(main):001:0> require 'team.rb'
=> true
irb(main):002:0> team = Team.new
=> #<Team:0x100391088 @members=[]>
irb(main):003:0> team.members = ['joshua', 'gabriel', 'jacob']
=> ["joshua", "gabriel", "jacob"]
irb(main):004:0> team.map{|member| member.capitalize}
=> ["Joshua", "Gabriel", "Jacob"]

Now we can call any Enumerable methods on our team itself, and it will assume we want to work with the members array within. Enumerable can be a powerful mix-in to your own classes. We can even take this a step further, and clean up our call to map:

team.map(&:capitalize)

If you haven’t seen this before, it’s called the unary ampersand operator, and it’s the subject of my next post.


Follow

Get every new post delivered to your Inbox.