Archive for the ‘Study’ Category

Retro-reading RailsSpace, part 2: link_to and Friends

March 15, 2009

This is Part 2 in my series Retro-reading RailsSpace. Despite the book being slightly out of date, and geared toward beginners, it’s a classic. I’m reading it (finally) and posting what I learn.

link_to has friends: link_to_if, link_to_unless, and link_to_unless_current

link_to has useful variations:

  • link_to_if: only make the name linked if the first param equates to true.
  • link_to_unless: only make the name linked if the first param equates to false.
  • link_to_unless_current: don’t create the link if it leads to the page you’re already on.

The first two take an extra parameter, prepended to the parameter list. That parameter is a conditional that needs to equate to true or false. link_to_unless_current doesn’t need an extra parameter, because it already knows what to look for. Here are some examples:

# user types: member, moderator, admin #

# generate a link only if the user is admin #
link_to_if current_user.admin?, 'admin', admin_path

# generate a link only if the user is NOT admin #
link_to_unless current_user.admin?, 'request admin status', request_admin_path

# generate this link only if we're not already on this page #
link_to_unless_current 'help', help_path

By default, all of these will display the same text you would have seen in the link, just not linked, if their conditions aren’t met. But that wouldn’t work too well for the admin/non-admin links, because we’d really rather hide them altogether. You can do this by passing in a block. With a block, you can respond to unmet conditions however you’d like. If the condition is NOT met, the link is not created, and the block is executed instead. The fun part is, that block can contain a link itself!

# generate an admin link, or request link, whichever is needed #
link_to_if current_user.admin?, 'admin', admin_path do
  link_to 'request admin status', request_admin_path
end

This might be handy, and I didn’t know it existed before RailsSpace.

Advertisements

Retro-reading RailsSpace: Symbols vs. Strings

March 15, 2009

I’ve started reading RailsSpace by Michael Hartl and Aurelius Prochazka. This 600 page book serves as a tutorial of Ruby on Rails that walks through building a social network, and you get to learn both virtually from scratch.

I put off reading this book for a couple reasons. It’s slightly outdated, and I’m not a beginner. But it’s a classic, and I was sure I’d pick up some new tricks along the way. I was right. I plan to keep reading, and chronical the things I learn.

Like most Ruby on Rails developers, I learned Ruby through Rails. While I’ve devoted more time to studying Ruby itself lately, it’s no surprise that my first lesson is Ruby-based. Symbols and Strings can often seem interchangeable, and convention tells us when it’s better to use one or the other. But now I know why.

Symbols are more efficient than strings, especially as hash keys. They lack most of the methods that weigh down a String object. In fact, a Ruby Symbol has just 12 documented methods – most of which handle conversion to a different format (#to_i, #to_s, etc). Strings, on the other hand, have over 10 times as many.

Symbol comparison is particularly speedy because symbols are added to a special (non-database) table, and looked up from there. Strings, on the other hand, compare character-by-character to determine if there is a match.

Let’s check it out in irb:

irb(main):001:0> "test".object_id
=> -605722338
irb(main):002:0> "test".object_id
=> -605736908
irb(main):003:0> :test.object_id
=> 83778
irb(main):004:0> :test.object_id
=> 83778

Aha! Two anonymous strings (not assigned to anything) are actually different objects, and their contents have to be compared to see if they’re equivalent. Calling :test, however, points to the same object no matter where it appears in your code.

So all Ruby has to do is verify if the two symbols being compared are, in fact, the same object. Comparing symbols is more like comparing integers than comparing strings, and that translates to speed in hash lookups, among other things.

If you’re really bored, you can read my unscientific test below.

Unscientific Test

I loaded one hash with 10,000 string keys (‘jaime1’ through ‘jaime10000’) and another hash with 10,000 symbol keys (:jaime1 through :jaime10000). Doing 3 million hash lookups took 14 cursor blinks on the hash with string keys. The same lookups took only 9.5 cursor blinks with symbol keys. See, I told you it wasn’t very scientific, but it did show about 33% speedier lookups with symbols.

Here’s the irb session:

# loading first hash with string keys #
string_hash = {}
10000.times {|i| string_hash["jaime#{i}"] = "jaime#{i}"}

# loading second hash with symbol keys #
symbol_hash = {}
10000.times {|i| symbol_hash[:"jaime#{i}"] = "jaime#{i}"}

# 3 milllion lookups on string-keyed hash: 14 cursor blinks #
1000000.times { string_hash['jaime1977']; string_hash['jaime429']; string_hash['jaime5000'] }

# 3 million lookups on symbol-keyed hash: 9.5 cursor blinks #
1000000.times { symbol_hash[:jaime1977]; symbol_hash[:jaime429]; symbol_hash[:jaime5000] }