Matthew Bass

Musings on software and life…

February 21st, 2010

Dirty date/time attrs in Rails lose their time zone

Dirty attributes were recently added to Rails and they’re quite useful. However, I ran into a problem where a dirty date/time attribute was losing its time zone information after a save. I was doing a comparison between two dates in a before_update callback like so:

before_update do
  if started_at.to_s(:abbrev_date) != started_at_was.to_s(:abbrev_date)
    errors.add :started_at, "cannot be set to a different day"
  end
end

The started_at date was coming back in the Eastern time zone as expected. The started_at_was attribute, which was supposed to reflect the value prior to the update, was coming back as a UTC date/time. I would expect it to be returned in the Eastern time zone too. Apparently, I’m not alone in this assumption because a ticket was opened for this issue last month.

An official fix hasn’t been made yet, but I got around the problem by calling in_time_zone on my dirty attribute:

before_update do
  if started_at.to_s(:abbrev_date) != started_at_was.in_time_zone.to_s(:abbrev_date)
    errors.add :started_at, "cannot be set to a different day"
  end
end
February 11th, 2010

Mass rename files in UNIX

Several of my Rails projects surface a RESTful API. I use integration tests to verify that the API calls work as expected. I also version my API calls so I can easily adapt the API to new circumstances while maintaining backwards compatibility.

To move to a new API version, I copy all of the existing integration tests and rename their prefix to the new version. Instead of renaming the files by hand, there is a nifty UNIX command that handles it for me. For example, to rename all the “v2_*.rb” files to “v3_*.rb” I would type:

for file in *; do mv "$file" "v3_${file#v2_}"; done
December 3rd, 2009

test_spec_on_rails now runs on Rails 2.3

If anyone still happens to be using test_spec, you’ll be thrilled to know that the test_spec_on_rails plugin is now compatible with Rails 2.3. It has also been converted to a gem. Install with:

sudo gem install test_spec_on_rails

Add to your Rails app’s test.rb like so:

config.gem 'test_spec_on_rails'

Enjoy the goodness of test-spec helpers from inside your Rails tests. Fork and submit patches via the GitHub project. Tell your friends. Donate money. Vote for Pedro.

December 3rd, 2009

Time warping gem goodness

The time zone warp code I posted about last week is now a gem:

sudo gem install time-zone-warp

To configure in your Rails app, add this line to the bottom of test.rb:

config.gem 'time-zone-warp', :lib => 'time_zone_warp'

You can also fork the code from the project on GitHub.

November 18th, 2009

Time zone warp

One of my Rails projects makes heavy use of time zones. I’ve run into some issues writing good tests for this type of thing. In particular, I’ve needed my tests to run within a time zone outside my own. But I don’t want to permanently change the time zone within the scope of the entire test run. I ended up coding this handler:

module ZoneWarp
  def pretend_zone_is(zone)
    original_zone = Time.zone
    begin
      Time.zone = zone
      yield
    ensure
      Time.zone = original_zone
    end
  end
end

Test::Unit::TestCase.send(:include, ZoneWarp)

Simply stick this code in a file inside your config/initializers directory (or include it from test_helper.rb or spec_helper.rb if you insist on doing it the right way) and you’re all set to write tests like this:

test "code works in other time zones" do
  pretend_zone_is "Mountain Time (US & Canada)" do
    # assertions go here
  end
end
June 17th, 2009

Radiant hack night

I attended my first Radiant hack night last week. We met at John’s apartment and spent several hours coding up new features for Radiant, which is an awesome Content Management System (CMS) built on Rails. Rick and John worked on a redesign of the admin backend, while Michael and I began adding support for using gems as Radiant extensions. There is still some work left to do, but we made decent progress.

I really enjoyed the experience. If you’re at all interested in learning more about Radiant, or helping to contribute, I encourage you to consider attending the next hack night. Make sure you’re on the raleigh.rb mailing list to receive notification when it gets scheduled.

June 3rd, 2009

Auto timeout sessions in Rails

Time Out!I released the initial version of my auto-session-timeout plugin for Rails at West End Ruby tonight.

Have you ever wanted to force your users off your app if they go idle for a certain period of time? Many online banking sites use this technique. If your app is used on any kind of public computer system, this type of functionality is essential for maintaining the privacy of your data.

After installing the plugin, a small snippet of JavaScript is placed on each page. The JS polls the server every minute to see if the session is still active. If the user has been idle for at least an hour, they are immediately redirected to a timeout page. The session will not timeout as long as the user keeps clicking around. The timeout and polling intervals are both configurable.

The plugin is dead simple to install and configure. To get started:

script/plugin install git://github.com/pelargir/auto-session-timeout.git

Then hit the README for step-by-step instructions.

May 8th, 2009

Introducing my latest Rails app: Fuelinator

Gas CanI started building Fuelinator at the last West End Ruby meetup. The motivation behind the project was the lack of a decent system for tracking my business mileage. Existing apps like Fuelly and My Mile Marker make it unnecessarily difficult to enter mileage, and the statistics they produce just aren’t that useful to me.

My initial goal with Fuelinator is to make mileage entry dead simple and to provide some compelling new features… for example, alerts via email or SMS when my vehicle’s mileage changes suddenly. This helps me track down maintenance problems early and gives me valuable information about what does and doesn’t improve my gas mileage. For example, I changed my air filter and inflated my tires last week. If my mileage changes drastically this week, I want to know. Now, Fuelinator will tell me.

The ultimate goal is for Fuelinator to save its users gobs of money on their gas bills. I haven’t made Fuelinator public yet, but if you’d like to participate in the beta program make sure you sign up. It’s going to be a fun ride!

April 13th, 2009

rspec’s route_for breaks when upgrading Rails

Came across this interesting test failure after upgrading a project to Rails 2.2.2 earlier today:

should route users's 'destroy' action correctly

The recognized options <{"action"=>"show", "id"=>"1",
"controller"=>"users"}> did not match <{"action"=>"destroy", "id"=>"1",
"controller"=>"users"}>, difference: <{"action"=>"destroy"}>

Turns out that rspec’s route_for method behaves differently when run against Rails 2.2+ due to the routing changes. The controller in question is setup as a resource, so the “destroy” action must be called via an HTTP DELETE, not a GET.

The failing line in the test looked like this:

route_for(:controller => 'users', :action => 'destroy', :id => 1).should == '/users/1'

The fix was simple enough:

route_for(:controller => 'users', :action => 'destroy', :id => 1).should == {:path => '/users/1', :method => :delete}

Hope this helps anyone who is experiencing the same problem.

November 19th, 2008

Fast Sphinx indexing with foxy fixtures

Can Sphinx and foxy fixtures place nicely together? Due to the way Sphinx indexing works, foxy fixtures will often slow down the indexing process drastically. This article explains how to overcome this limitation.