» tagged pages
» logout

sorted by: recent | see : popular
Content Tagged with & + tricks

Cloning Ubuntu Hardy image in VMWare Fusion

Having spent the better part of a day googling and struggling, I figured it would possibly benefit others if I took a minute to post the steps I took to clone a VMWare Fusion image. The image in question is of Ubuntu Server (Hardy). I’m using VMWare Fusion 2 (beta 2).

Just find your “Virtual Machines” folder (should be in your Documents folder), and copy the image in question to a new location. (The images are actually folders; a simple “cp -R” worked fine for me.)

Then, open the copied image in VMWare Fusion and boot it. VMWare Fusion will ask if you if you copied or moved the image—be sure to say you copied it (that let’s VMWare set up a new MAC address for your image).

Go ahead and log in once the server boots. You’ll find networking is all hosed. To fix networking, this worked for me:

  • “sudo hostname blah”, to set the hostname. This doesn’t change it permanently, so you’ll also want to:
  • “sudo vim /etc/hostname”. Change the contents of the file to the hostname you want. Then:
  • “sudo vim /etc/hosts”. Replace all mentions of the old hostname with the new hostname.
  • “sudo vim /etc/udev/rules.d/70-persistent-net.rules”. There will be two entries in this file. The first points eth0 at the old MAC address, and the second points eth1 at the new. Go ahead and delete the first entry, and change “eth1” to “eth0” in the second (and now only) entry.
  • “sudo shutdown -r now” to restart your virtual machine.

Once your machine comes back up, you should have a network again! Now, if only VMWare Fusion could bake all this in somehow… :/

(Related: installing VMWare Tools on Ubuntu server. It’s from 2006, but it still worked well enough for me, though I followed the instructions for tweaking the network that the VMWare Tools install gave at the end, rather than what this gent said.)

Capistrano: the { buckblogs :here } - Home

Plugin Spotlight: Article Image Fetchy

Today I’d like to highlight the mephisto_article_image_fetchy plugin, from the twisted mind of courtenay. It scans the article body for any image tags, creates assets from any remote images, and replace the URLs in the body of the article. (see included image as an example, linked from here).

For any plugin developers, notice how this uses a module and #include_into to extend Article, and the little-known #body_doc method to grab an HTML::Document of the article body. I actually added #body_doc to the filtered_column plugin so that more plugins like this could be made without having to generate the document multiple times.

mephisto: Mephisto News

New Contact Feedback Plugin

James Crisp wrote a nifty Contact Feedback plugin for Mephisto for the new Thoughtworks Studios site. The plugin looks nice, and fills a common need in Mephisto. Also, the Thoughtworks Studios site is extremely well-done. I had seen it before, but didn’t realize it used Mephisto. Major kudos to James Crisp and Thoughtworks!

For anyone that asks: it looks like the main difference between this, and my own feedback plugin is that mine doesn’t send emails. It stores them in the DB and lets you browse in the admin. Nice since your inbox doesn’t get the spam, but I’ve been finding that I often forget to check it :)

mephisto: Mephisto News

Creating a Mephisto Theme Using Liquid

Jon Baker wrote a great article on creating Mephisto themes. There’s also a nifty Liquid for Mephisto PDF cheatsheet by George that was released on the same day.

Finally, who posted as Dr Acula in the previous post? Totally awesome…

mephisto: Mephisto News

Net::SSH::Multi + Rake == Tasty Potential

Last night I released the first preview of Net::SSH::Multi (gem install --source http://gems.jamisbuck.org net-ssh-multi). Today, let me show you a tasty hint of what you can do with it.

Consider the following Rakefile:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
def remote
  @remote ||= begin
    require 'net/ssh/multi'

    session = Net::SSH::Multi.start

    session.via 'gateway.host', session.default_user

    session.group :web => session.use('web1', 'web2')
    session.group :app => session.use(*(1..8).map { |n| "app%02d" % n })
    session.group :db  => session.use('db1', :properties => { :primary => true })

    session
  end
end

namespace :remote do
  task :hostnames do
    remote.exec("hostname").wait
  end

  task :app_hostnames do
    remote.with(:app).exec("hostname").wait
  end

  task :web_hostnames do
    remote.with(:web).exec("hostname").wait
  end
end

You can now do things like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
$ rake remote:hostnames
(in /home/jamis)
[web1] web1.host
[app02] app02.host
[app05] app05.host
[app03] app03.host
[app06] app06.host
[app08] app08.host
[db1] db1.host
[app01] app01.host
[web2] web2.host
[app04] app04.host
[app07] app07.host

The Net::SSH::Multi library is still experimental, but it is stable and full-featured enough that I seriously considered implementing the next release of Capistrano on top of it. (I’ll probably put that off until cap3, though, due to the magnitude of the change.) If you do something cool with it, let me know!

Capistrano: the { buckblogs :here } - Home

Plugin Spotlight: Article Image Fetchy

Today I’d like to highlight the mephisto_article_image_fetchy plugin, from the twisted mind of courtenay. It scans the article body for any image tags, creates assets from any remote images, and replace the URLs in the body of the article. (see included image as an example, linked from here).

For any plugin developers, notice how this uses a module and #include_into to extend Article, and the little-known #body_doc method to grab an HTML::Document of the article body. I actually added #body_doc to the filtered_column plugin so that more plugins like this could be made without having to generate the document multiple times.

mephisto: Mephisto News

New Contact Feedback Plugin

James Crisp wrote a nifty Contact Feedback plugin for Mephisto for the new Thoughtworks Studios site. The plugin looks nice, and fills a common need in Mephisto. Also, the Thoughtworks Studios site is extremely well-done. I had seen it before, but didn’t realize it used Mephisto. Major kudos to James Crisp and Thoughtworks!

For anyone that asks: it looks like the main difference between this, and my own feedback plugin is that mine doesn’t send emails. It stores them in the DB and lets you browse in the admin. Nice since your inbox doesn’t get the spam, but I’ve been finding that I often forget to check it :)

mephisto: Mephisto News

Creating a Mephisto Theme Using Liquid

Jon Baker wrote a great article on creating Mephisto themes. There’s also a nifty Liquid for Mephisto PDF cheatsheet by George that was released on the same day.

Finally, who posted as Dr Acula in the previous post? Totally awesome…

mephisto: Mephisto News

Plugin Spotlight: Article Image Fetchy

Today I’d like to highlight the mephisto_article_image_fetchy plugin, from the twisted mind of courtenay. It scans the article body for any image tags, creates assets from any remote images, and replace the URLs in the body of the article. (see included image as an example, linked from here).

For any plugin developers, notice how this uses a module and #include_into to extend Article, and the little-known #body_doc method to grab an HTML::Document of the article body. I actually added #body_doc to the filtered_column plugin so that more plugins like this could be made without having to generate the document multiple times.

mephisto: Mephisto News

New Contact Feedback Plugin

James Crisp wrote a nifty Contact Feedback plugin for Mephisto for the new Thoughtworks Studios site. The plugin looks nice, and fills a common need in Mephisto. Also, the Thoughtworks Studios site is extremely well-done. I had seen it before, but didn’t realize it used Mephisto. Major kudos to James Crisp and Thoughtworks!

For anyone that asks: it looks like the main difference between this, and my own feedback plugin is that mine doesn’t send emails. It stores them in the DB and lets you browse in the admin. Nice since your inbox doesn’t get the spam, but I’ve been finding that I often forget to check it :)

mephisto: Mephisto News

Creating a Mephisto Theme Using Liquid

Jon Baker wrote a great article on creating Mephisto themes. There’s also a nifty Liquid for Mephisto PDF cheatsheet by George that was released on the same day.

Finally, who posted as Dr Acula in the previous post? Totally awesome…

mephisto: Mephisto News

Creating a Mephisto Theme Using Liquid

Jon Baker wrote a great article on creating Mephisto themes. There’s also a nifty Liquid for Mephisto PDF cheatsheet by George that was released on the same day.

Finally, who posted as Dr Acula in the previous post? Totally awesome…

mephisto: Mephisto News

Creating a Mephisto Theme Using Liquid

Jon Baker wrote a great article on creating Mephisto themes. There’s also a nifty Liquid for Mephisto PDF cheatsheet by George that was released on the same day.

Finally, who posted as Dr Acula in the previous post? Totally awesome…

mephisto: Mephisto News

Plugin Spotlight: Article Image Fetchy

Today I’d like to highlight the mephisto_article_image_fetchy plugin, from the twisted mind of courtenay. It scans the article body for any image tags, creates assets from any remote images, and replace the URLs in the body of the article. (see included image as an example, linked from here).

For any plugin developers, notice how this uses a module and #include_into to extend Article, and the little-known #body_doc method to grab an HTML::Document of the article body. I actually added #body_doc to the filtered_column plugin so that more plugins like this could be made without having to generate the document multiple times.

mephisto: Mephisto News

New Contact Feedback Plugin

James Crisp wrote a nifty Contact Feedback plugin for Mephisto for the new Thoughtworks Studios site. The plugin looks nice, and fills a common need in Mephisto. Also, the Thoughtworks Studios site is extremely well-done. I had seen it before, but didn’t realize it used Mephisto. Major kudos to James Crisp and Thoughtworks!

For anyone that asks: it looks like the main difference between this, and my own feedback plugin is that mine doesn’t send emails. It stores them in the DB and lets you browse in the admin. Nice since your inbox doesn’t get the spam, but I’ve been finding that I often forget to check it :)

mephisto: Mephisto News

Faking cursors in ActiveRecord

There are times (like, in a migration, or a cron job) where I want to operate on large numbers of rows in the database, such as for billing, where you want to select all accounts who are due for automatic renewal, or when adding a new column to a table that you need to prepopulate with computed data.

One way to do that is just to brute force it:

1
2
3
Account.find(:all).each do |account|
  # ...
end

The drawback here is obvious: when you’re dealing with hundreds of thousands or even millions of rows, selecting them all into memory at once is brutal. And since ActiveRecord doesn’t support cursor-based operations, you can’t just ask ActiveRecord to return the rows as it reads them.

Here’s a trick I’ve been using recently to query large result sets while being friendly to the computer:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class <<ActiveRecord::Base
  def each(limit=1000)
    rows = find(:all, :conditions => ["id > ?", 0], :limit => limit)
    while rows.any?
      rows.each { |record| yield record }
      rows = find(:all, :conditions => ["id > ?", rows.last.id], :limit => limit)
    end
    self
  end
end

Account.each do |account|
  # ...
end

Sadly, this won’t work on every DBMS, or with every query; it exploits several idiosyncrasies of MySQL which might not be present on other DBMSs:

  • MySQL sorts indexes.
  • The primary key is an index.
  • Queries which MySQL determines can be best satisfied by the primary key, then, will be returned in sorted order.

This means that if you try to add additional conditions to the query, you’ll also need to add an :order clause to sort by the id…and this will more than likely cause the performance of the query to go down the tubes. But for those queries where you just want to select every row anyway, it works quite well. You could use OFFSET and LIMIT, but OFFSET begins to be really, really slow when the OFFSET is in the tens of thousands or higher because it has to count through that many rows before finding where to begin returning data. Basing the query on id, like this, has the advantage of speed, because the database can use indexes like it was meant to.

Capistrano: the { buckblogs :here } - Home

ActiveRecord::Base#find shortcut

I use ActiveRecord::Base#find a lot in the Rails console. A lot. As a result, I’ve started doing the following:

1
2
3
class <<ActiveRecord::Base
  alias_method :[], :find
end

That little snippet saves me up to five entire keystrokes, every time I need to do a find!

1
2
3
prs = Person[5]
prs = Person[:first]
prs = Person[:all, :conditions => { :name => "Jamis" }]

And, thanks to the existing hash and array semantics, it loses none of find’s readability for most cases. Good stuff!

Capistrano: the { buckblogs :here } - Home

New Contact Feedback Plugin

James Crisp wrote a nifty Contact Feedback plugin for Mephisto for the new Thoughtworks Studios site. The plugin looks nice, and fills a common need in Mephisto. Also, the Thoughtworks Studios site is extremely well-done. I had seen it before, but didn’t realize it used Mephisto. Major kudos to James Crisp and Thoughtworks!

For anyone that asks: it looks like the main difference between this, and my own feedback plugin is that mine doesn’t send emails. It stores them in the DB and lets you browse in the admin. Nice since your inbox doesn’t get the spam, but I’ve been finding that I often forget to check it :)

mephisto: Mephisto News

Raising the right exception

Ruby makes it very easy to raise exceptions:

1
2
3
4
def finagle_something
  raise "need a block" unless block_given?
  ...
end

Using raise like that (with just the exception message) is really handy for quick-and-dirty solutions. But for Serious Business Stuff™ you may often find the ambiguity of the default RuntimeError a little frustrating.

Ruby has a bunch of predefined exception classes that you can use. For the above, you’d do better to raise an ArgumentError, specifically (raise ArgumentError, "need a block"). It can pay big dividends to become familiar with the standard exception hierarchy in Ruby.

Sometimes, though, the standard exception classes just aren’t enough. For example, in Capistrano 2.0, I’d like any exception that Capistrano itself raises to be immediately recognizable as a Capistrano exception. The solution?

1
2
3
4
5
module Capistrano
  class Error < RuntimeError; end
  class ConnectionError < Error; end
  ...
end

Now, clients of Capistrano only need to look for Capistrano::Error to safely catch any exceptional conditions within Capistrano:

1
2
3
4
5
def use_capistrano
  ...
rescue Capistrano::Error => error
  warn "couldn't do a capistrano thing: #{error.message}"
end

Furthermore, the benefits of having more specific exception classes (like Capistrano::ConnectionError) are manifold; you can write code to easily detect and retry certain errors, or report some problems differently than others. When you start using specific exception classes, instead of the default RuntimeError, you’ll find you can handle your exceptions much more gracefully, and write much more robust programs.

Capistrano: the { buckblogs :here } - Home

Rendering empty responses

Sometimes (and especially once you start dealing with writing web services) you’ll find yourself wanting to return an empty response, with only a status code and (possibly) a few headers set.

You can do this easily enough using the render method:

1
2
headers['Location'] = person_url(@person)
render :nothing => true, :status => "201 Created"

That, however, is unbearably verbose, especially when you find yourself needing to do it in multiple places.

Enter the head method:

1
head :created, :location => person_url(@person)

There, isn’t that beautiful?

Capistrano: the { buckblogs :here } - Home

Poor-man's pagination

Here’s a really simple little tip, related to displaying paginated results. Using offset/limit, it’s pretty trivial to pull back just the page of data you want, as long as you know what the last offset/limit values were:

1
2
3
rows = Person.find(:all, :conditions => { ...},
  :limit => page_size, :offset => last_offset + page_size)
more_results = (last_offset + page_size + rows.length) < Person.count

However, it’d be nice to do this in a single query, especially since Person.count can get spendy if there are a lot of rows in the database. Here’s a simple way to do it:

1
2
3
rows = Person.find(:all, :conditions => { ...},
  :limit => page_size+1, :offset => last_offset + page_size)
more_results, rows = rows.length > page_size, rows[0,page_size]

You query the database for one more row than you actually want (page_size+1). If you get that many rows back, then you know there is at least one more page of data after the current page.

Capistrano: the { buckblogs :here } - Home

Dereferencing fixtures

I frequently find myself writing a lot of helper methods for my tests. (I think I picked up that habit from Marcel Molina, Jr., actually.) These helper methods encapsulate tasks that I wind up doing all over the place, things like logging in a user, or uploading a file.

However, sometimes I want to pass in a symbol identifying the fixture that should be used in the helper, and sometimes I want to pass a record in directly. To accommodate this, I’ve been using the following idiom in my helpers:

1
2
3
4
def login!(user)
  user = users(user) if Symbol === user
  ...
end

It just checks the argument, and if it is a Symbol, it dereferences it using the “users” method provided by the fixtures.

To make this idiom reusable, I’ve got this little gem in my test_helper.rb file:

1
2
3
4
5
6
7
def dereference(argument, collection)
  if Symbol === argument
    return send(collection, argument)
  else
    return argument
  end
end

The login! method would then be written like this:

1
2
3
4
def login!(user)
  user = dereference(user, :users)
  ...
end

It’s a little thing, but it sure makes those test helpers a lot more flexible!

Capistrano: the { buckblogs :here } - Home

Route#to_s

Here’s a nifty trick. Route#to_s exists. Why is this cool?

1
2
3
ActionController::Routing::Routes.routes.each do |r|
  puts r
end

This will give you a list of all of the routes you have defined, in a very human-consumable format. It’s great if you are trying to figure out why Rails is having problems accepting a URL that you think it should be accepting.

Similarly, you can list all of your named routes:

1
2
3
ActionController::Routing::Routes.named_routes.routes.each do |name, route|
  puts "%20s: %s" % [name, route]
end

This is especially handy if you are using map.resources, where there are lots of named routes being generated for you behind the scenes.

Capistrano: the { buckblogs :here } - Home

begin + else

Even after 6+ years, Ruby still continues to surprise and delight me. My latest discovery (thanks to Mauricio’s Happy 2007 challenge) is that begin/end blocks accept (in addition to rescue and ensure) an else clause:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
begin
  # main code here
rescue SomeException
  # ...
rescue AnotherException
  # ..
else
  # stuff you want to happen AFTER the main code,
  # but BEFORE the ensure block, but only if there
  # were no exceptions raised. Note, too, that
  # exceptions raised here won't be rescued by the
  # rescue clauses above.
ensure
  # stuff that should happen dead last, and
  # regardless of whether any exceptions were
  # raised or not.
end

If you don’t have an ensure clause, else is pretty much the same as just putting code immediately after the end, but if the order matters (something should happen before ensure, and only if the main code succeeded, and should not be subject to being rescued if something goes wrong), then else is your man.

Capistrano: the { buckblogs :here } - Home

Infinity

This is hardly an original trick (it’s been mentioned many times before, on countless other blogs) but it is useful enough that it deserves mention yet again.

Ruby won’t let you divide an integer by zero—you’ll get an exception. However, thanks to the IEEE 754 standard for floating point numbers, when you try to divide a float by zero you get a rather special value back:

1
2
puts 1.0/0
#-> Infinity

It’s not a constant though, it’s just how that floating point result is represented as a string. However, you can easily assign that value to a constant:

1
Infinity = 1.0/0

Once you have that, you can use it for all kinds of nifty things; throw it in ranges, use it in comparisons, whatever suits your fancy:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# a rather useless range
everything = -Infinity..Infinity
puts everything.include?(5) #-> true

# use it for representing an unbounded value
storage_limits => { :demo => 0,
  :standard => 250.megabytes,
  :expert => 1.gigabyte,
  :unlimited => Infinity }

if bytes_used < storage_limits[account_level]
  # add another file or something
else
  # display "out of space" message
end

Like I said earlier, it’s old news, but no less handy for that.

Capistrano: the { buckblogs :here } - Home

Overriding attributes in ActiveRecord

I love that super calls method_missing if the method is not defined on the superclass.

Consider this case. You have some ActiveRecord named Account, which has an associated email_address. However, an account owner may optionally give a special “notification” email address, which will be used for things like newsletter emails and security issues and such. If no notification address has been explicitly given, it should fall back to the account’s primary email address. It’s as simple as this:

1
2
3
4
5
class Account < ActiveRecord::Base
  def notification_address
    super || email_address
  end
end

Calling super forces the superclass, ActiveRecord::Base, to be sent the notification_address message, which it won’t understand. This causes method_missing to be called on AR::Base, which looks for the notification_address attribute in the record’s attribute set. If that has not been set, it will be nil, in which case we then default to the email_address value.

Just as you’d expect.

Capistrano: the { buckblogs :here } - Home

Nesting resources

The RESTful routes feature in Rails makes it really, really simple to nest resources within each other. Just give a block to the “map.resources” call, and define further resources on the value yielded to that block:

1
2
3
4
5
6
7
map.resources :accounts do |accounts|
  accounts.resources :people do |people|
    people.resources :notes do |notes|
      notes.resources :comments
    end
  end
end

That monstrosity would allow you to define routes like:

1
2
3
4
5
6
7
8
accounts_url         #-> /accounts
account_url(1)       #-> /accounts/1
people_url(1)        #-> /accounts/1/people
person_url(1,2)      #-> /accounts/1/people/2
notes_url(1,2)       #-> /accounts/1/people/2/notes
note_url(1,2,3)      #-> /accounts/1/people/2/notes/3
comments_url(1,2,3)  #-> /accounts/1/people/2/notes/3/comments
comment_url(1,2,3,4) #-> /accounts/1/people/2/notes/3/comments/4

Simple! However, in using RESTful routes more and more, I’m coming to realize that this is not a best practice. Rule of thumb: resources should never be nested more than 1 level deep. A collection may need to be scoped by its parent, but a specific member can always be accessed directly by an id, and shouldn’t need scoping (unless the id is not unique, for some reason).

Think about it. If you only want to view a specific comment, you shouldn’t have to specify the account, person, and note for the comment in the URL. (Permission concerns can come into this, to some degree, but even then I’d argue that judicious use of the session is better than complicating your URLs.) However, if you want to view all comments for a particular note, then you do need to scope the request by that note. Given the above nesting of routes, I’m finding the following a better (if slightly more verbose) method:

1
2
3
4
5
6
7
8
9
10
11
12
13
map.resources :accounts do |accounts|
  accounts.resources :people, :name_prefix => "account_"
end

map.resources :people do |people|
  people.resources :notes, :name_prefix => "person_"
end

map.resources :notes do |notes|
  notes.resources :comments, :name_prefix => "note_"
end

map.resources :comments

You’ll notice that I define each resource (except accounts) twice: once at the top level, and once nested within another resource. For the nested resources, I also give a “name_prefix”—this gets tacked onto the front of the named routes that are generated.

So, the above mappings give you the following named routes:

1
2
3
4
5
6
7
8
accounts_url          #-> /accounts
account_url(1)        #-> /accounts/1
account_people_url(1) #-> /accounts/1/people
person_url(2)         #-> /people/2
person_notes_url(2)   #-> /people/2/notes
note_url(3)           #-> /notes/3
note_comments_url(3)  #-> /notes/3/comments
comment_url(4)        #-> /comments/4

The URL’s are shorter, and the parameters to the named routes are much simpler. It’s an all-around win! I won’t go so far as to say that resources should never be deeply nested, but I will say that you should think long and hard before you go that route.

Capistrano: the { buckblogs :here } - Home

Per-developer configuration

Here’s another trick you can do with your environment.rb file. It’s of dubious value, but if you’re working on a team with conflicting opinions, it might be a handy way to set your own defaults without tyrannically checking them into the team’s source repository.

Just throw the following bit into the bottom of your environment.rb file:

1
2
3
4
if RAILS_ENV != "production" 
  railsrc = "#{ENV['HOME']}/.railsrc" 
  load(railsrc) if File.exist?(railsrc)
end

Then, if you put a file named ”.railsrc” in your home directory, your application will look for and load it every time the environment.rb file is loaded (unless you’re in production mode). Your .railsrc might look something like this:

1
2
ActiveRecord::Base.colorize_logging = false
# other stuff your apps configure

What other stuff would you put in a per-developer configuration file?

Capistrano: the { buckblogs :here } - Home

More on watching ActiveRecord

Remember Watching ActiveRecord Do Its Thing, where I talked about redirecting the log to STDOUT when using the console? I’ve got a new trick based on this that I’ve found quite helpful. Simply put the following snippet in your config/environment.rb:

1
2
3
4
def log_to(stream)
  ActiveRecord::Base.logger = Logger.new(stream)
  ActiveRecord::Base.clear_active_connections!
end

Now, when you’re at the console, you can just do:

1
2
3
4
5
6
>> log_to STDOUT
=> ...
>> Post.find(:first)
  Post Load (0.000138)   SELECT * FROM posts LIMIT 1
=> #<Post:0x1234 ...>
>>

The best part is, by clearing the active connections after setting the logger, you can change the logger at any time, even after you’ve made any number of find calls.

And, you can pass your own stream objects into it:

1
2
3
4
5
6
7
8
9
>> buffer = StringIO.new
=> ...
>> log_to buffer
=> ...
>> Post.find(:first)
=> #<Post:0x1234 ...>
>> p buffer.string
=> "  \e[4;35;1mPost Load (0.000138)\e[0m   \e[0mSELECT * FROM posts LIMIT 1\e[0m\n"
>>

Why would you want to do this? Well, for one thing, you can use log_to in your tests, and make sure that sensitive things like credit card numbers aren’t being written to your logs. Or, you can use this in tests to make sure that your latest optimization really does reduce the number of queries made to the database.

Good fun!

Capistrano: the { buckblogs :here } - Home

Unit vs. Functional vs. Integration

Unit tests. Functional tests. Integration tests. Rails draws a lot of circles around your tests, and it does a good job (in general) of helping you know what kinds of tests belong in each, but there are still some gray areas (and areas that I think it categorizes incorrectly).

For example: when do you use a functional test, and when do you use an integration test? Googling will point you at a variety different opinions, but here’s my take on it.

Unit tests are for testing models and pseudo-models. Basically, they are the simplest of your tests, exercising very specific functionality. Rails also throws your ActionMailer tests in this group, but I think that’s wrong. ActionMailer objects are more like controllers than like models, so I generally move my mailer tests to the functionals.

Functional tests bypass a lot of the start-up processes of Rails: they don’t try to recognize any routes, they ignore your instructions regarding your sessions, and they don’t do any request parsing. They depend heavily on the TestRequest and TestResponse classes, which stub out much of the basic functionality of the request and response objects.

As a result, functional tests are fast (since they skip so much initialization), and they are excellent at testing the meat of your controllers. However, because they require you to explicitly instantiate the controller you want to test (take a look at the setup method that Rails generates for you), they are harder to use in cross-controller scenarios. Also, if you want to make sure your routes are processed by the correct controllers and actions, functional tests don’t make that very easy, either.

Integration tests, on the other hand, test the entire Rails stack. Each request in an integration test mimics a real web request and exercises routing recognition, actually parses incoming requests, uses real sessions, and so forth. As a result, integration tests are significantly slower than functional tests, but they are excellent at testing cross-controller stories. Want to make sure the flash you set in the “create” action is being properly displayed in the “index” action? Sounds like you need an integration test. You can even use integration tests to exercise entire stories: “user logs in, views the catalog, views a product, adds it to their cart, checks out, enters credit card, submits payment, sees invoice.”

Integration tests are also good for grouping a bunch of related tests that cut across controllers, like permissions and access control. Even though each individual test might only test a single controller, each one is testing a different controller, and rather than have all your access control tests spread across several files in the “functional” directory, it is more convenient (and maintainable) to group them into a single integration test suite.

Naturally, your application may have some classes that don’t fit cleanly into any of the above three categories. What about a service that runs via cron? What about code that processes incoming emails? As a rule of thumb, if your test focuses on very specific functionality and tests only a single model, put it in the “unit” directory. If it tests something that depends on your models (like a controller, mailer, or other service), put it in the “functional” directory. And if you are testing something that cuts across multiple controllers or services, or if you want to aggregate tests across multiple controllers, then those belong in an integration test.

Capistrano: the { buckblogs :here } - Home

Testing your views

Here’s a quick little “advice” tip: don’t use assertions to test the structure of your views.

That is to say, don’t do this:

1
2
3
4
5
#make sure the text field is in the table cell
assert_select "table td input[type=text]"

# make sure the person's name is in the h2 header tag
assert_select "h2", person.name

Why not? Because you want your views to be very fluid. You want to keep the cost of change is so low that you have no hesitation to jump in and rearrange things to make the view cleaner. If you are using explicit tag names in your tests, you reduce that fluidity. Your views become rigid, because your tests imply that using anything but a table to format your form is wrong. Want to use an h1 for the person’s name, or a div? Don’t you dare, it’ll break the tests.

The better way to test your views is to think about what you are really wanting to test. First of all, don’t test static content, like table structures and the order of form fields on a page. Instead, test the dynamic parts of your view, especially those parts that are subject to conditional rendering. Secondly, test semantically, not syntactically. That is to say, don’t base a test on the type of the tag, but rather on what you want the content to represent. Use CSS classes and DOM id’s instead of explicit tag names.

Here’s a concrete example. Suppose you have a view like this:

1
2
3
4
5
<% if @user.administrator? %>
  Hi <%= @user.name %>! You appear to be an administrator.
  <%= link_to "Click here", admin_url, :id => "admin_link" %>
  to see the admin stuff!
<% end %>

The only really significant thing you ought to be testing here is that the admin link only shows up for administrators. You might also want to test that the link points to where you expect it to, though that’s a lower importance.

1
2
3
4
5
6
7
8
9
10
11
def test_admin_sees_link
  # set up session for an admin user first, and then:
  get "index"
  assert_select "#admin_link"
end

def test_non_admin_does_not_see_link
  # set up session for a normal, non-admin user first, and then:
  get "index"
  assert_select "#admin_link", false
end

Arranging your tests like this will make them less likely to break on cosmetic tweaks, which will increase your confidence in your tests and your willingness to tweak your views.

Capistrano: the { buckblogs :here } - Home

Object#with_options

In Named, explicit routes I mentioned Object#with_options in passing, only to discover later that this super-useful method is not documented in Rails’ API docs! I’ve since corrected the situation in trunk, but the method is useful enough (particularly in conjunction with routing) that I figured it was worth blogging about.

The pain point that inspired the method is this: suppose you have a bunch of method calls, all of which accept an options hash as the last parameter, and all of which share one or more of the same options. Route definitions are the canonical examples of this:

1
2
3
4
map.create_message "/msg/create/:id", :controller => "message", :action => "create"
map.delete_message "/msg/delete/:id", :controller => "message", :action => "delete"
map.message "/msg/:id", :controller => "message", :action => "get"
# etc, etc, etc

Ugly! And definitely not very DRY. One way around this is to define a separate variable that contains the hash of common options, and use Hash#merge to add in the difference in each call

1
2
3
4
5
common = { :controller => "message" }
map.create_message "/msg/create/:id", common.merge(:action => "create")
map.delete_message "/msg/delete/:id", common.merge(:action => "delete")
map.message "/msg/:id", common.merge(:action => "get")
# etc, etc, etc

Better, but still not very DRY. Object#with_options is Rails’ answer to this pattern:

1
2
3
4
5
6
map.with_options :controller => "message" do |msg|
  msg.create_message "/msg/create/:id", :action => "create"
  msg.delete_message "/msg/delete/:id", :action => "delete"
  msg.message "/msg/:id", :action => "get"
  # etc, etc, etc
end

Ah! Duplication, be gone! Much nicer.

Although I’ve personally used this primarily in route definitions, it can be used anywhere that option hashes appear as the last parameter…which describes most of the interfaces in Rails. Have a bunch of associations on a model, all of which are declared dependent on the parent?

1
2
3
4
5
6
7
class Blog < ActiveRecord::Base
  with_options :dependent => :destroy do |parent|
    parent.has_many :authors
    parent.has_many :posts
    parent.has_many :themes
  end
end

Great stuff! (And yet another example of the power of blocks in Ruby.) For the curious, you read can read the implementation of with_options in Rails’ ActiveSupport project, here and here. All told, it’s under 30 lines of code, so it’s pretty easy to grasp. (Props to Sam Stephenson for the beautiful implementation!)

Capistrano: the { buckblogs :here } - Home

Named, explicit routes

Names routes are hotsauce. We are all forever indebted to Marcel Molina, Jr. and his gift for elegant API’s. Without him, we’d still be stuck in the quagmire that is “map.connect”.

These days, I don’t use map.connect at all. Named routes for everything. Does that seem too extreme?

Let me clarify a bit. I don’t use map.connect with implicit routes. And just what is an implicit route? This is:

1
map.connect ":controller/:action/:id"

That’s an implicit route, because it implicitly maps any number of paths to any number of controllers and actions. Contrast that with an explicit route:

1
map.connect "/people/:id", :controller => "people", :action => "show"

The controller and action are now hardwired into the route. And if you’ve gone that far, you might as well go with a named route, too, since you can then access it directly:

1
map.person "/people/:id", :controller => "people", :action => "show"

So, why do I favor explicit routes over implicit routes? Consider some of the issues with implicit routing:

  • If you want to temporarily “turn off” one of your controllers (say, you’re having problems with your RSS feeds and need to disable them for a bit), you have to somehow make sure the controller file can’t be found by the routing code, which means removing it, obfuscating it’s name, or some other hack. Using named routes, you just comment out the routes that point at the controller in question, and you’re all set.
  • Say your application is a year old or so (ancient!) and has an established base of users, who have all bookmarked various areas of your app. Now, you go and refactor things, so that an action that used to be in one controller is now in another, and so forth. With implicit routes, you’re hosed, but with explicit routes your users’ bookmarks will continue to function as before, since the route that gets recognized remains unchanged—it simply points to a different place now.
  • Implicit routes are extremely concise to define, but very verbose to use, since you often have to give the controller and action in the options to link_to, or url_for, or whatever you use. Sure, your routes.rb file is only one line long, but how much more did you have to type in your views?

Furthermore, I prefer named routes over unnamed routes, for a few reasons.

  • Route generation using implicit routes is ugly, both internally and externally. I mean, seriously, who wants to type “link_to(person.name, :controller => ‘person’, :action => ‘show’, :id => person)” when they can type “link_to(person.name, person_url(person))”. It gets even worse if you want to pass HTML options to link_to, because you have to use explicit curly braces around the route options in that case. Named routes are, as I said, hotsauce.
  • You can use named routes in functional and integration tests. Pretty cool! In functional tests, you can do “assert_redirected_to(person_url(people(:bob)))”. In integration tests, you