Update: Daniel has a great post that explains the idea behind “Sessions”.
We’re really excited to announce Sessions by Collective Idea on June 23-26. Come spend 4 days in Holland, Michigan, learning Ruby and Rails. Whether you’re a Ruby newbie, or want to get better, this Session is for you.
This Session features hands-on training by people who know Rails inside and out, and have taught Ruby, Rails, and Rails deployment across the globe.
In your free time, you’ll get to explore Holland’s unique downtown, the fantastic sand dunes of Lake Michigan, or talk to other Rubyists over drinks.
Register today and save 20%. We look forward to seeing you!
So by now we all know how to do wicked-cool search with acts_as_ferret. (If not, the RailsEnvy guys can lend a hand, but the tutorial is a little outdated for the latest trunk version of acts_as_ferret. Just replace #find_by_contents with #find_with_ferret and you should be good.)
But searching a single model is so last year. All the cool kids are getting promiscuous with their searches and involving multiple models. Fortunately for us, recent revisions of acts_as_ferret makes this easy-peasy.
The key to making this happen is a shared index: we want all of our models indexed in one place so ferret only has to do one search. We can do it without a shared index, but then we have to do a ferret search and thus a SQL select for each model. Plus, if we want your search results interspersed and sorted by rank, we have to have a shared index.
Enough chit-chat, show us how!
Ok, I’m getting to it. Grab the latest version of acts as ferret from trunk:
script/plugin install svn://projects.jkraemer.net/acts_as_ferret/trunk/plugin/acts_as_ferret
Now, instead of defining acts_as_ferret in our models, we define them all in config/aaf.rb
ActsAsFerret::define_index('shared',
:models => {
Person => {:fields => [:first_name, :last_name, :phone, :bio]},
Company => {:fields => [:name, :description]},
Post => {:fields => [:title, :body]}
},
:ferret => {
:default_fields => [:first_name, :last_name, :phone, :bio, :name, :description, :title, :body]
}
)
This defines a new index, called “shared”, and then defines the acts_as_ferret configuration for each model.
Now for the fun part: searching our shiny new index.
def search
@results = ActsAsFerret.find(params[:q], 'shared')
end
This will give us one array with any models that matched the search query, ordered by rank. And for those times when we only want to search one model, we can still do that.
def search
@people = Person.find_with_ferret(params[:q])
end
How do we display the results?
Update: Sorry, originally I had an example using resources, but that doesn’t work as-is; I was doing something a little different in the app that this example came from.
To display our search results, we just render a partial for each model in the result:
<% @results.each do |result| %>
<%= render :partial => "search/#{dom_class(result)}" %>
<% end %>
This will just look for a partial for each model (like search/_person.html.erb).
So there you have it. Now you too can have promiscuous searching.
Update: I’ve put together an example rails app that uses the shared index. It uses sqlite and has some date pre-populated. Start up script/server and do a search for “John”.
At Collective Idea, we have a plugin called awesomeness that is…well, awesome. It’s a collection of things that we use in almost every project that aren’t generic enough to go into individual plugins (although some things may have evolved enough to be worthy of plugin status).
A while ago, I blogged a little snippet for backing up your remote database. Well, that snippet as evolved quite a bit, into it’s own set of rake and Capistrano tasks.
First, the rake tasks. You Can easily create a new local backup:
$ rake db:backup:create
This creates a backups directory in your project, with a subdirectory for each backup based on the timestamp. A backup consists of the schema.rb file and then a fixture for each table to hold the data. Why fixtures? Good question. Because we wanted the backups to be database independent.
You can easily restore your local database to the latest backup, or a specific version:
$ rake db:backup:restore VERSION=20080427214315
That’s nice, but what good are local backups? That’s where Capistrano comes in. Just add this to your config/deploy.rb:
load 'awesomeness/backup'
This adds some nifty remote backup support. Now, whenever cap deploy:migrations is run, a backup of your remote database will automagically be created and stored in the shared directory on the server. You can also have them transferred to your local machine by adding a callback in your deploy.rb:
after "backup:create", "backup:download"
Sometimes, you just want to take a snapshot of the server and plop it into your local database.
$ cap backup:mirror
How do I get this backup awesomeness?
Awesomeness now lives on Github (like the rest of the world). Fork it and let us know what you think.
I got to feel the pain of being stuck behind an HTTP proxy this week while working at Xerox’s office in El Segundo, CA. It sucked. You don’t realize how much you use the internet until you can’t get to half of the sites that you use every day.
So, in an effort to sympathize with other poor souls that are stuck behind a proxy during the work day, I added proxy support to Tinder:
c = Tinder.new('subdomain', :proxy => 'http://user:pass@proxy.example.com:8000')
I don’t actually have access to testing this, so I’d appreciate if someone behind a proxy could check out the code from git and confirm that it works, and then I will put out a new release.
Speaking of git, I’m now only pushing changes to git. The subversion repository will stay around but will not be kept up to date.
With great power comes great responsibility.
I’ve been leading Ruby and Rails training over the last couple weeks for a company in Brisbane, Australia, Xerox in El Segundo, CA, and yellowpages.com in Glendale, CA. Visiting companies is always so interesting because you get to see how different people work together and how they go about solving problems. You also get to see some really interesting code.
I was helping one of the companies walk through some code they inherited from an acquisition and came across something similar to this wonderful snippet of code:
class NilClass
def method_missing(method, *args)
raise(NoMethodError, "undefined method '#{method}' for nil")
rescue => e
CustomLogger.error(e)
nil
end
end
WTF? They’re overriding #method_missing on nil to raise an exception, they then proceed to rescue it, log the error, and return nil!
I’m guessing they had some buggy code that was calling a method on nil, causing a NoMethodError to be raised. And instead of fixing the code, they just decided to change it so that you could call methods on nil and it would just silently fail.
>> nil.foo.bar.baz
=> nil
It took me a while to figure out why they were raising an error and then rescuing it, but I’m guessing it’s so they have access to a stack trace in the logger.
I’ll give them credit for being creative, but whoever wrote that piece of code doesn’t deserve to be using Ruby. Yes, Ruby’s open classes are powerful, but that’s just ridiculous.
I’m not a fan of social networking sites in general, but there are two that I have found really useful.
Shelfari
It’s not the first of it’s kind, but Shelfari is a great site for exploring and sharing books with friends. It seems like people don’t talk enough about good books that they’ve read (or maybe I just don’t spend enough time at the bar), so Shelfari seems like a good way to follow what your friends are reading.

Dopplr
Dopplr is one of those sites that I didn’t know I wanted until I started using it (like extra-chunky spaghetti sauce). It lets you keep track of your planned trips, and then tells you when other people you know are going to be in the area. Dopplr can import iCalendar files, so if you’re using a decent calendaring app, it takes absolutely no effort to keep it up to date.
So check out Shelfari and Doppler and look me up.
While we’re not exactly freelancers at Collective Idea, we operate very much like freelancers; we are contractors that work mostly out of our homes on client projects. We share many of the benefits that freelancers enjoy, and experience many of the same challenges. In the coming days and maybe weeks, I will try to post some of the things I’ve found helpful from personal experience.
Seriously, take a shower, every day! Not only that, but take a shower first thing in the morning.
Working from home, it’s easy to get into the habit of stumbling out of bed, occasionally making a quick pass through the kitchen, and plopping down right at your desk. There were often days weeks where I would go straight from bed to my office and start working, not pausing to shower until mid-morning, noon, or sometimes even after work.
I’ve found that showering early in the morning has been helpful for several reasons:
- Consistency: We are creatures of habit, and that is a good thing. We live in natural rhythms, and the beats that we move to are important for productivity. I’ll talk more about this in my next post.
- Transition: When I first started working from home, what I missed the most was the drive or walk from home to work, and back again. Without it, I found it very difficult to make the mental transition from personal life to professional life. The two would often blur and I would spend the first half of my day distracted by personal matters while I was consumed by work in the evenings. Showering has become my morning transition. I take care of personal matters when I wake up–breakfast, bills, laundry, etc–and begin working immediately after I shower and get dressed.
- Freshness: water is very refreshing, both physically and mentally. While I’m not one of them, many people find that they do their most creative thinking in the shower. But I do find that after I shower I’m very refreshed and sharp.
So there you have it: proper hygiene is as important for your professional life as it is for your personal life.
Up next: you’re a professional, show it with your hours.
This post is somewhat different from the typical format of this blog, so I’d love to hear your feedback. Also, I’m interested in any tips you may have as a freelancer or independent consultant. Send me an email or post your tips in the comments.
I’ll be leading another hands-on, interactive workshop exploring the ins and outs of Ruby on Rails in San Francisco on April 1–4. Experience the Rails way of approaching web applications, starting with the basics of Ruby and Rails, and then diving into the full Rails’ MVC stack, testing techniques, Ajax and even web services. In the 4 day class, we’ll work through the full life-cycle of a Rails project, giving you experience with all facets of a typical app, lead by people that have been working with Rails every day for 2 years.
Sign up now on Marakana’s website and receive $150 off using the coupon code “collectiveidea”.
The RSpec team is hoping to move to some form of distributed version control, giving both git and Mercurial a test run. This month, they’re checking out git.
You can clone the git repository using:
git clone git://gitorious.org/rspec/mainline.git rspec
Jared Kuolt has put together a cool little app that lets you use Jabber with campfire. The app simply uses Tinder to listen in on a campfire room, forwarding messages on to a Jabber account, and posting any messages it receives from Jabber. Very cool.


While trying to debug some HTTP code, I wanted to be able to see what the actual HTTP request looked before it was sent. So, I added a #to_s method:
require 'stringio'
class Net::HTTPGenericRequest
def to_s
io = StringIO.new
exec(io, '1.1', path)
io.string
end
end
All the built in requests extend HTTPGenericRequest, so now I can call #to_s on any request:
request = request = Net::HTTP::Get.new('/some/path')
request.set_content_type 'text/html'
request.basic_auth 'username', 'password'
puts request.to_s
Which gives me:
GET /some/path HTTP/1.1
Accept: */*
Content-Type: text/html
Authorization: Basic dXNlcm5hbWU6cGFzc3dvcmQ=
I had also intended to add a #to_s method to the response, but it wasn’t obvious how to accomplish that, and I found my bug before I needed it. So, if anyone feels ambitious…
A week or so ago, 37 Signals released an update to Campfire that broke the ability to listen in a room with Tinder. Version 0.1.5 of Tinder has been released, which fixes the Room#listen method.
Maybe you’ve heard of it, but there’s this fancy web framework called Ruby on Rails. Apparently it’s all the rage these days. It’s only 2.0 right now, so the big kids say it still belongs on the playground, but there’s rumors of people using it to do real work. The word on the street is that it makes you more productive and makes programming fun again. If that sounds like something you’d like to learn, you can get more information and signup on Marakana’s website.
Update: Marakana is offering $150 off when you sign up using coupon code “collectiveidea”!
I ran across this issue several weeks ago, but it came up at the latest Grand Rapids Ruby Group meeting, so I thought I would share it.
Ruby’s require, for better or worse, doesn’t expand paths. As the docs point out, require 'a'; require './a' will load a.rb twice. This doesn’t matter most of the time, but there’s one place it’s used often that will bite you: tests and specs.
Every Rails’ test has a line similar to this:
require File.dirname(__FILE__) + '/../test_helper'
This doesn’t normally cause any problems, as long as every test has an identical require statement. Where you start to get into problems is when you have tests in a nested subdirectory (like test/controllers/admin/users_controller_test.rb), in which case the require statement would look like this:
require File.dirname(__FILE__) + '/../../test_helper'
require sees this as a different file and will re-load it. This still shouldn’t hurt you unless you’re doing something in test_helper.rb that would be changed by loading it twice (like aliasing a method). This also effects RSpec with requiring spec_helper.rb
The solution? Expand the path yourself.
require File.expand_path(File.dirname(__FILE__) + '/../../test_helper')
It’s not really clear to me why Ruby’s require works this way. You would think a method that was intended to only load a file once would make sure that it never re-loaded the same file, no matter how it was referenced. It definitely doesn’t adhere to the “principle of least surprise”. Any idea why?
Several people have reported that acts_as_audited does not work with ActiveScaffold. I don’t use ActiveScaffold, so I had no motivation to fix it. But thanks to a tip from Aaron, this has now been fixed.
To make acts_as_audited work with ActiveScaffold, only enable auditing for only the :create, :update, and :destroy actions.
class ApplicationController < ActionController::Base
audit User, Thing, :only => [:create, :update, :destroy]
end
I’m not sure exactly why it breaks or why this fixes it, but from this thread it sounds like ActiveScaffold just doesn’t support polymorphic associations, which is what acts_as_audited uses to associated audits with models.
View archives for May 2008.