making things better, making better things

Monday, August 10, 2009


This weekend RailsBridge ran its first Rails BugMash:

The idea is simple: RailsBridge has a lot of energy. The Rails Lighthouse has a lot of open tickets. With the help of some Rails Core team members, we’re going to see what we can do to cut down the number of open tickets, encourage more people to get involved with the Rails source, and have some fun.

Definitely a success – reportedly at least 120 tickets were closed, I’m sure a lot of new people got involved, and the people on #railsbridge seemed to be having fun.

posted by erik at 10:34 am  

Saturday, June 27, 2009

deploying Thinking Sphinx on DreamHost PS

The time had come to add a search engine to Touring Machine. I went pretty far down the road with Xapian/Xapit, but:

You may want to trigger [reindexing] via a cron job on a recurring schedule (i.e. every day) to update the Xapian database. However it will only take effect after the Rails application is restarted because the Xapian database is stored in memory.

I see the Xapit Sync project to fix this has since ceased to be vaporware. Well, maybe next time.

Anyway, so RubyTrends tells me the cool kids use Thinking Sphinx, and I want to be cool, but I’m running Touring Machine on the cheap – on a shared DreamHost server – and they don’t want me to run server processes, and although some guy on the Internet says it’s probably fine, I’m leery of defying them. But last week they were running a discount offer on DreamHost PS, their quasi-VPS service – no root, but you can run whatever you want, within the resources (memory, CPU) you pay for.

Sounds like a fine place to run the search engine, but I didn’t want to run the whole Rails app there – since I’ve already got a place to run it that is effectively free. (DreamHost is very cheap, and I run a bunch of sites on it.) So I set out to run a distributed site, with the web app running on DreamHost shared hosting, and the search engine running on DreamHost PS.

It took some setup, but I think I’ve got it working. Here are some notes. As usual, this isn’t a tutorial. You should read everyone else’s instructions – especially the official Thinking Sphinx documentation, and J. Wade Winningham’s post about Capistrano tasks. (I didn’t use his deploy.rb, though.)

posted by erik at 5:47 pm  

Friday, June 12, 2009

where it’s at

With the infrastructure in place for the suggestions feature, it’s easy to add new kinds of suggestions – especially if someone else has already done most of the work. For example, given an address, we should be able to look up the names of businesses at that address, and suggest them as venue names.

Yahoo! and Google both do this automatically if you search for something they recognize as an address. But Google doesn’t seem to provide an API. Yahoo! Local does, and the YM4R gem already provides a nice Ruby wrapper for it. So:

  def make_suggestions_based_on_address
    businesses = Ym4r::YahooMaps::BuildingBlock::LocalSearch::get(
      :location => address.block,
      :radius => 0.001,
      :results => 20,
      :query => '*'
    businesses.each do |business|
      add_suggestion(:name, business.title)
      add_suggestion(:url, business.business_url) unless business.business_url.blank?

You might wonder about the radius parameter. Technically, Yahoo! doesn’t provide the service I want; I want “tell me what’s at this address”, it has “tell me what’s near this address”. With a radius of 0, it returns up to 10 results. After a little experimentation, it looks to me like 0.01 is a tight enough radius to get me all the businesses at an address – or at least the top 10 – and none of the ones next door.

This is actually one of two ways I’m subverting the API here. It’s intended for search, not simple lookup, which is why it’s a little awkward to get a simple address. It’s also why Yahoo! provides multiple URLs for each business. The BusinessUrl is the actual URL for the business’s web site. There’s also a BusinessClickUrl, which “contains extra information that helps [them] to optimize [their] search services. Yahoo! requests that you display the BusinessUrl, but link to the BusinessClickUrl, so they can track usage.

The latest code actually uses both URLs, but I’m going to stop here for now.

posted by erik at 12:22 am  

Wednesday, June 10, 2009

how to help

Here’s how the suggestions feature for Touring Machine works so far.


  • As the user enters data in the new venue form, if we’re able to make any guesses, we pop them up in a panel to the right of the form.
  • Each suggestion is a link. If a user clicks a suggestion link, the suggestion is copied into the corresponding form field, and the field is given focus, so the user can edit it. (For example, if the “page title” suggestion has additional text around the venue name.)

There’s also an “accessible” JavaScript-free UI, but it’s bad, so I’m going to pretend it’s not there.

Client and Server

I started drawing an interaction diagram, but it’s really standard Rails stuff:

  • Model, controller, and view produce the new venue form.
  • When any form input’s value changes, we submit the whole form (as an AJAX GET) to the controller’s suggest action.
  • The server responds with an RJS view that populates and shows the suggestions panel (if there are any suggestions) or hides it (if not).
  • The suggestions are links that call a JavaScript function that copies, highlights, and focuses.
  • Once the user is done editing, the create action just works as normal.


In keeping with the Skinny Controller, Fat Model approach, the only interesting code is in the model. It took me a couple of tries to get a design I liked, but eventually I went with Rails-style magic:

  def make_suggestions
    @suggestions = {}
    methods.grep(/^make_suggestions_based_on_/).each do |method|
      attrs = method.sub('make_suggestions_based_on_', '').split('_and_')
      values = {|attr| send(attr)}
      send(method) unless values.any?(&:blank?)

When asked for suggestions:

  • We look through the Venue object for methods of the form make_suggestions_from_attr_and_other_attr. (We support multiple attributes so that, for example, given a venue name and vague address – city and state – we can look up the exact address.) Call these “suggesters”.
  • We call each suggester only if we have non-blank values for all the named attributes (because how are you going to base a suggestion on the venue’s address if you don’t know its address?). Note that although I’m saying “attributes”, this code works for attributes, associatons, and in fact any method. This is important because a venue’s address is actually a has_one association.
  • The suggesters populate @suggestions, and then we return it.

A small thing I’m pleased by: The make_suggestions method works both as “create suggestion objects” and in the idiomatic sense of “make a suggestion” as “suggest something”.

posted by erik at 1:55 pm  

Saturday, May 23, 2009

Why I switched from acts_as_authenticated to Clearance, and why I didn’t need to

What happened, see, was that I finally started using my aforementioned old Rails app in earnest, and when I did, I discovered that… I couldn’t log out. I didn’t actually need to log out, but it bugged me. I dug around a little. I could log out in development mode, but not production mode. The logout method thought it was working, but when the next page loaded I was still logged in. Something to do with sessions and cookies.

Something down in the depths of the authentication system, and I thought, well, I could try to debug this ancient plugin that I didn’t write, and that has probably never been updated to newer versions of Rails… or I could try out one of those new systems I’ve been reading about. That have documentation, and support, and Rails 2.3 compatibility. How hard could it be?

posted by erik at 4:02 pm  

Saturday, May 23, 2009

how I switched from acts_as_authenticated to Clearance

This week I updated the authentication system in an old Rails app from the pre-REST acts_as_authenticated plugin to thoughtbot’s shiny new Clearance gem. What follows isn’t a how-to (because really, who else is going to be making this switch?) but it might be useful for someone. May the Great Gazoogle guide them to these shores.

posted by erik at 3:39 pm  

Monday, May 11, 2009

I uncorrupted a git database!

… but it was touch and go there for a while.

RubyMine is out, and I’d felt positive enough about the beta that I wanted to give it a try… but I didn’t want to do it in any existing working directory, in case it did stupid stuff with my files. So, simple enough, just clone the git repository:

[556] RubymineProjects $ git clone ~/Documents/workspace/tourette
Initialized empty Git repository in /Users/eostrom/RubymineProjects/tourette/.git/
fatal: object 3a37e547408f1f955337bade61807ef021608760 is corrupted

Fatal?!? I don’t like the sound of that.

posted by erik at 5:45 pm  

Saturday, April 25, 2009

Rails 2.3 backtraces and emacs

This morning I exhumed an old Rails project and started cranking it forward from Rails 1.2.2 to the current version, 2.3.2. That’s about two years of Rails develpopment. This afternoon I got all the tests passing except for two (and I think they’re failing because Yahoo has changed its geocoder)… and then I found the other stash of tests. So, still working on it.

I spent some time tonight sidetracked by tools. In Emacs, thanks to Ryan Davis, I can shift-mouse-3 on pretty much any line in a stack trace and be taken to the right line in the right file. But under Rails 2.3 it doesn’t always work: (more…)

posted by erik at 9:54 pm  

Saturday, April 18, 2009

I’m at GoGaRuCo

… the Golden Gate Ruby Conference. Three talks I like so far, for different reasons: (more…)

posted by erik at 12:07 pm  

Thursday, April 9, 2009

RubyMine (IDEA for Ruby)

Quick thoughts on trying out the RubyMine IDE (based on IntelliJ IDEA) today: (more…)

posted by erik at 11:13 pm  
« Previous PageNext Page »

Powered by WordPress