Announcing: Sessions by Collective Idea

collectiveidea | sessions | training May 15 2008
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!

posted by brandon | updated May 16th 10:59 AM | 0 comments

Using shared indexes with acts_as_ferret

ferret | rails | search April 28 2008

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”.

posted by brandon | updated May 11th 10:32 PM | 22 comments

Awesomeness: database backups

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.

posted by brandon | updated May 1st 10:01 AM | 2 comments

Proxy support for Tinder

campfire | proxy | ruby | tinder April 18 2008

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.

posted by brandon | updated April 18th 04:33 AM | 0 comments

Daily WTF: NilClass#method_missing

code | nil | ruby | wtf April 18 2008

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.

posted by brandon | updated April 18th 03:28 AM | 3 comments

Social Sites you should check out

links | social March 26 2008

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.

posted by brandon | updated March 26th 11:56 PM | 0 comments

Tips for freelancers: take a shower

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:

  1. 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.
  2. 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.
  3. 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.

posted by brandon | updated March 20th 01:26 AM | 6 comments

Ruby on Rails Training in San Francisco: April 1–4

collectiveidea | rails | ruby | training February 28 2008

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”.

posted by brandon | updated February 28th 01:16 PM | 2 comments

RSpec flirts with git

git | rspec | ruby February 28 2008

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
posted by brandon | 1 comment

Camper: Jabber for Campfire

campfire | jabber | ruby | tinder | xmpp February 18 2008

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. Adium chat window

Campfire chat window

posted by brandon | updated February 16th 12:59 PM | 2 comments

Getting a glimpse into Net::HTTP requests

core_ext | http | ruby | stdlib February 16 2008

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…

posted by brandon | updated February 17th 12:08 PM | 1 comment

Tinder fixed after Campfire update

campfire | gem | ruby | tinder January 25 2008

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.

posted by brandon | updated January 25th 12:33 AM | 1 comment

Ruby on Rails Training in San Francisco, Jan 29–Feb 1

collectiveidea | rails | ruby | training January 11 2008

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”!

posted by brandon | updated January 16th 09:44 PM | 0 comments

Ruby's require doesn't expand paths

rspec | ruby January 08 2008

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?

posted by brandon | updated January 8th 11:32 PM | 5 comments

acts_as_audited and ActiveScaffold

acts_as_audited | plugin | rails December 13 2007

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.

posted by brandon | updated December 13th 06:53 PM | 0 comments

View archives for May 2008.

About

I'm Brandon Keepers, a web application developer that likes beautiful code, valid markup and adherence to standards. As a part of Collective Idea in Holland, Michigan, I practice Agile software development primarily using Ruby on Rails.

-86.103171 42.785037

Contact:

more »

Syndicate