Category Archives: Ruby

Reduce ‘N’ DB Updates to 1 When Using `touch: true`

TL;DR Use the activerecord-delay_touching gem to speed up writes in your rails app by consolidating touch calls into a single UPDATE round-trip to the database.


Did you know that a single call to ActiveRecord#save can result in hundreds of database round-trips?

In this post I’ll show you how to fix it without using no_touching. no_touching is fine for when you don’t care about tracking when your records were updated, but frequently you do need to track that. For example, when you are using fragment caching or Russian doll caching, you need updated_at to be correct.

In the middle of last year, when I was consulting on a Spree project, I found that ActiveRecord’s touch: true can result in an enormous number of redundant UPDATE calls to the database. In my case there was potential to update hundreds of child objects in a single action, which resulted in hundreds of touch calls to a single parent object—and this caused hundreds more cascading touch calls to the parent’s parent. There was a noticeable effect on performance.

Although I encountered this problem in Spree, it is not Spree-specific. It is a general problem any time you use touch: true and your controller can update many child objects in a single action.

A good example of this is accepts_nested_attributes_for, which lets you mass-update attributes of child records in a has_many relationship by making a single call to ParentObject.save. But if the child class has touch: true on the belongs_to statement (e.g. for fragment caching), Rails calls touch on the parent object N times—where N is the number of child objects. Another example is when giving the user a bunch of checkboxes so they can indicate which objects are related. (See HABTM Checkboxes and HABTM Checkboxes (revised)).

In all these cases, the parent object only needs to be touched once. Touching it lots of times slows down response time (yes I measured it) and puts unnecessary load on the database.

To solve it, I created a small gem called activerecord-delay_touching. Its API is modeled after the no_touching method that was introduced in Rails 4.1. Except that instead of not touching, it batches up the touches into the smallest possible number of touch calls.

Usage:

ActiveRecord::Base.delay_touching do
  # ...code that results in `touch` being called...
end

When the end of the block is reached, all the batched-up touches are reduced and executed. They occur synchronously. It does not run in a background processor. This is by design—running in the background would screw up subsequent requests that depend on updated_at, such as in cache keys.

In addition, the gem consolidates touches across multiple rows in each table. For example, if touch was called on two Person objects with ids 1 and 2, it will make a single call to update updated_at where people.id in (1,2).

And, finally, it captures and reduces cascading touches. In other words if, while running through all the after_touch calls, more touch calls occur, it batches them up and runs them together in a second pass.

It keeps doing this until there are no more touches, or until the sun swallows up the earth. Whichever comes first.

There are a couple of things to be aware of when using the gem. Read the “Gotchas” section of the README.

The gem is well-tested. It has thorough specs, and it has been used in production for six months.

If you’d like to use it or contribute, please do. Here’s the source. Check out the README for more examples.

Introducing Whiny Validation. So You Can Figure Out Why Your Rails Specs Failed.

whining_boySometimes when I write a spec in a Rails app, it fails silently but it isn’t clear why. For example, here’s a pretty standard (if minimal) controller spec:

  describe "POST 'create'" do
    it "makes a new customer" do
      post :create
      expect(response).to redirect_to Customer.last
    end
  end

Or perhaps you would use expect { post :create } to change { Customer.count }.by(1). Either way, I run this spec, and the error message doesn’t give me enough information about why it failed:

$ rspec spec/controllers/customers_controller_spec.rb
F

Failures:

  1) CustomersController POST 'create' makes a new customer
     Failure/Error: expect(response).to redirect_to Customer.last
       Expected response to be a <:redirect>, but was <200>
     # /Users/brian/.rvm/gems/ruby-1.9.3-p385/gems/rspec-expectations-2.13.0/lib/rspec/expectations/fail_with.rb:32:in `fail_with'
     # /Users/brian/.rvm/gems/ruby-1.9.3-p385/gems/rspec-expectations-2.13.0/lib/rspec/expectations/handler.rb:33:in `handle_matcher'
     # /Users/brian/.rvm/gems/ruby-1.9.3-p385/gems/rspec-expectations-2.13.0/lib/rspec/expectations/expectation_target.rb:34:in `to'
     # ./spec/controllers/customers_controller_spec.rb:8:in `block (3 levels) in <top (required)>'
...

How would you debug this to figure out what you did wrong? One thing you could do: look at the log. But it doesn’t help much:

Processing by CustomersController#create as HTML
   (0.1ms)  SAVEPOINT active_record_1
   (0.1ms)  ROLLBACK TO SAVEPOINT active_record_1
  Rendered customers/new.html.haml within layouts/application (0.2ms)
Completed 200 OK in 55ms (Views: 41.0ms | ActiveRecord: 1.7ms)
  Customer Load (0.6ms)  SELECT "customers".* FROM "customers" ORDER BY "customers"."id" DESC LIMIT 1
   (0.1ms)  ROLLBACK

Hmm, no clues there. At this point, if a code inspection doesn’t help, I would typically resort to inserting a debugger statement or various puts statements. It’s not a very efficient way to work.

But I’ve noticed that frequently, this type of spec failure is due to an input validation error. That’s why I created the Whiny Validation gem.

Whiny Validation watches for ActiveRecord validation errors on all models. Whenever one occurs, it logs the validation message and dumps the ActiveRecord object (with inspect) to the log. All you have to do is search the log for the word “validation,” or browse through the log and the yellow text should jump out at you.

To make it work, simply add this to your Gemfile:

gem 'whiny_validation'

Now rerun the spec and look at the log:

Processing by CustomersController#create as HTML
   (0.1ms)  SAVEPOINT active_record_1
  Validation failed  #<Customer id: nil, email: nil, created_at: nil, updated_at: nil>
    => Email can't be blank
   (0.1ms)  ROLLBACK TO SAVEPOINT active_record_1
  Rendered customers/new.html.haml within layouts/application (0.2ms)
Completed 200 OK in 28ms (Views: 11.7ms | ActiveRecord: 2.3ms)
  Customer Load (0.5ms)  SELECT "customers".* FROM "customers" ORDER BY "customers"."id" DESC LIMIT 1
   (0.1ms)  ROLLBACK

Let’s see that in full color:

Whiny Validation

That’s much better. It tells me that a validation failed, it shows the object that had the failure, and it shows the validation error message. Now it’s easy to see my mistake: I forgot to pass in an email address to the “create” action in my spec. When I change the spec to this, it passes:

post :create, customer: { email: "test@example.com" }

How Does it Work?

Here is the entire implementation, with the exception of the configuration code:

module WhinyValidation
  extend ActiveSupport::Concern

  included do
    after_validation :whiny_validation,
      :if => proc { |model| model.errors.present? }
  end

  def whiny_validation
    ActiveSupport::Notifications.instrument(
      "validation_failed.whiny_validation",
      :object => self,
      :error_messages => errors.full_messages)
  end

  class LogSubscriber < ActiveSupport::LogSubscriber
    def validation_failed(event)
      debug do
        name = color("Validation failed", YELLOW, true)
        object = event.payload[:object]
        error_messages = color(
          event.payload[:error_messages].map {|message|
            "    => #{message}"
          }.join("\n"), YELLOW
        )

        "  #{name}  #{object.inspect}\n#{error_messages}"
      end
    end
  end

  WhinyValidation::LogSubscriber.attach_to :whiny_validation
end

module ActiveRecord
  class Base
    include WhinyValidation
  end
end

Let’s break this down. First, let’s look at the beginning and the end of the file:

module WhinyValidation
  extend ActiveSupport::Concern

  included do
    after_validation :whiny_validation,
      :if => proc { |model| model.errors.present? }
  end
end

module ActiveRecord
  class Base 
    include WhinyValidation
  end
end

ActiveSupport::Concern lets me be notified when this module is included elsewhere, using the included statement. At the end of the file, I include WhinyValidation in ActiveRecord::Base. The included statement gets run, so it adds an after_validation callback to every subclass of ActiveRecord::Base. The callback calls my whiny_validation method if any errors were detected during validation.

Next, let’s take a look at the whiny_validation method itself:

  def whiny_validation
    ActiveSupport::Notifications.instrument(
      "validation_failed.whiny_validation",
      :object => self,
      :error_messages => errors.full_messages)
  end

What I want to do is write to the logfile. I could just have written logger.debug, but I want to use color in my message and ActiveSupport::LogSubscriber has helper methods for writing to the log with color. So I call ActiveSupport::Notifications.instrument (which means “broadcast a notification”) and I pass two things:

  1. A string with two parts, separated by a dot: first the name of an event, followed by a namespace. (I’m not sure why the namespace comes last. It feels backward to me.)
  2. The payload, which is a hash. What belongs in the payload? It’s up to you when you define a notification. I decided I include the ActiveRecord object whose validation failed, and the full list of error messages.

Next, someone has to listen to the notification and do the logging. I created a class named LogSubscriber in the WhinyValidation namespace, and made it a subclass of ActiveSupport::LogSubscriber so I can use that color method:

  class LogSubscriber < ActiveSupport::LogSubscriber
    def validation_failed(event)
      debug do
        name = color("Validation failed", YELLOW, true)
        object = event.payload[:object]
        error_messages = color(
          event.payload[:error_messages].map {|message|
            "    => #{message}"
          }.join("\n"), YELLOW
        )

        "  #{name}  #{object.inspect}\n#{error_messages}"
      end
    end
  end

The first line of validation_failed is debug do. Since we’re in a subclass of ActiveSupport::LogSubscriber, methods are defined for all the logger levels. You don’t have to call Rails.logger.debug, just call debug. (Actually, the real implementation calls send(WhinyValidation.configuration.log_level), because the log level is configurable. I simplified it for this blog post.)

By the way, most people don’t realize that when you call the logger, you are allowed to pass in a block. Whatever the block returns gets converted to a string with .to_s and then is output to the log. I used that trick here so that in any environment that doesn’t have the log_level set to debug, the code doesn’t have to waste time constructing a message.

Next, I call ActiveSupport::LogSubscriber‘s helper method color and pass in the YELLOW constant (also defined in ActiveSupport::LogSubscriber), to colorize the “Validation failed” string. The true means “make it bold.”

Then I do the same thing with the error messages, making them yellow and concatenating them.

The last thing I do is return a string which includes the “Validation failed” message, an inspection of the object that was invalid, and the list of error messages.

Finally, we have to hook it up:

  WhinyValidation::LogSubscriber.attach_to :whiny_validation

The last line is calling a method whose implementation is in the base class, ActiveSupport::LogSubscriber. It tells my LogSubscriber class to watch for ActiveSupport notifications that use the “whiny_validation” namespace. Whenever one occurs, it extracts the event name (in this case, “validation_failed”) and looks for a method by that name. If it exists, it calls it and passes in an event object.

One of the methods on the event object is payload, which returns the hash that I passed in.

Conclusion

This turned out to be pretty easy because:

  1. Ruby lets you extend existing classes, so I was able to inject my own after_validation hook into ActiveRecord::Base.
  2. ActiveSupport::Notifications and ActiveSupport::LogSubscriber work together to make it really easy to log anything that broadcasts a notification, and to log with color.

Go ahead and use this in your projects. Please let me know if you liked it.

One last note: if you want to configure it to log at the :info level or any other level, take a look at the README. It tells you how.

Establishing a Connection to a Non-Default Database in Rails 3.2

If you’ve ever built a Rails app in which some models don’t connect to the default database, you know that establish_connection is the method you would call make the connection.

But before I get to that: the space shuttle Endeavor flew directly over my street today, low and slow, with a fighter jet escort. My neighbors and I had an amazing view of it. It was piggybacked on a 747 transport for a publicity tour across California before being retired at a Southern California museum. It was exciting!

Shuttle Flyover

So. Let’s say you needed to talk to an external NASA database. You would create new keys in database.yml called nasa_development, nasa_test, and nasa_production:

# database.yml
development:
  # development configuration goes here

nasa_development:
  # development configuration to external database goes here

# same for test and production...

Then define your models like this:

class Astronaut < ActiveRecord::Base
  establish_connection "nasa_#{Rails.env}"
end

In this example, Rails looks for an ‘astronauts‘ table in the external database. (Automatic table naming still works. You can override that too, by calling self.table_name=).

In the past, when I’ve had multiple tables on a single connection, I always included a module that makes the connection. Let’s define models for Astronaut and Shuttle:

module NasaConnection
  extend ActiveSupport::Concern
  included do
    establish_connection "nasa_#{Rails.env}"
  end
end

class Astronaut < ActiveRecord::Base
  include NasaConnection
end

class Shuttle < ActiveRecord::Base
  include NasaConnection
end

That might have been overkill. I could just as well have done this:

class Astronaut < ActiveRecord::Base
  establish_connection "nasa_#{Rails.env}"
end

class Shuttle < ActiveRecord::Base
  establish_connection "nasa_#{Rails.env}"
end

In both of these techniques, establish_connection is called twice. This works in Rails 3.1.8 and earlier, but starting in 3.2.0 you will get runtime errors. An example:

class Astronaut < ActiveRecord::Base
  establish_connection "nasa_#{Rails.env}"
  has_many :missions
  has_many :shuttles, through: :missions
end

class Shuttle < ActiveRecord::Base
  establish_connection "nasa_#{Rails.env}"
  has_many :missions
  has_many :astronauts, through: :missions
end

class Mission < ActiveRecord::Base
  establish_connection "nasa_#{Rails.env}"
  belongs_to :astronaut
  belongs_to :shuttle
end

# test
shuttle = Shuttle.create name: "Endeavor"
shuttle.astronauts << Astronaut.create(name: "Mark Kelly")
assert_equal 1, shuttle.reload.astronauts.count # FAIL

Different database adapters will give you different errors. (I tried SQLite and Postgresql.) The problem is in ActiveRecord, not in the adapters.

Trying to Find a Fix

The fact that this doesn’t work any more seems to me like a bug in ActiveRecord. So I used a debugger to step through the establish_connection code in Rails 3.1.8 and 3.2.8, trying to identify the problem. I found a comment above the definition of the ConnectionHandler class that gave me a hint:

# suppose that you have 5 models, with the following hierarchy:
#
# |
# +-- Book
# | |
# | +-- ScaryBook
# | +-- GoodBook
# +-- Author
# +-- BankAccount
#
# Suppose that Book is to connect to a separate database (i.e.
# one other than the default database). Then Book, ScaryBook
# and GoodBook will all use the same connection pool. Likewise,
# Author and BankAccount will use the same connection pool.
# However, the connection pool used by Author/BankAccount
# is not the same as the one used by Book/ScaryBook/GoodBook.

Ah! So maybe ActiveRecord requires you to create a common base class for all models that will talk to the same external database. So I tried it. Notice that Astronaut, Shuttle, and Mission are all subclasses of NasaTable, which is a subclass of ActiveRecord::Base:

class NasaTable < ActiveRecord::Base
  establish_connection "nasa_#{Rails.env}"
end

class Astronaut < NasaTable
  has_many :missions
  has_many :shuttles, through: :missions
end

class Shuttle < NasaTable
  has_many :missions
  has_many :astronauts, through: :missions
end

class Mission < NasaTable
  belongs_to :astronaut
  belongs_to :shuttle
end

# test
shuttle = Shuttle.create name: "Endeavor"
shuttle.astronauts << Astronaut.create(name: "Mark Kelly")
assert_equal 1, shuttle.reload.astronauts.count

This code, like my earlier code, worked great in Rails 3.1. But it still failed in Rails 3.2, only now for a different reason: ActiveRecord tried to connect to a table called ‘nasa_tables‘. I thought it must be associating all three subclasses with that table.

Hmm, easy but annoying to fix, right? Force Rails to use the right table names:

class Astronaut < NasaTable
  self.table_name = 'astronauts'
  ...
end

class Shuttle < NasaTable
  self.table_name = 'shuttles'
  ...
end

class Mission < NasaTable
  self.table_name = 'missions'
  ...
end

Nope, that still didn’t work. Rails was still looking for the nonexistent ‘nasa_tables‘ table. Looks like self.table_name= is not going to solve this particular problem.

MoonEventually I found a discussion of a Rails issue where someone was having this problem. In their example, A was the base class and B was the subclass. @tenderlove said, “Out of curiosity, why would you do this? If there is no A table, you should set the class to be abstract.”

Abstract? I know how to define abstract classes in other languages like C++ but I’ve never heard of an abstract class in Ruby. Well, it turns out he’s talking about an ActiveRecord concept, not a Ruby concept. Any subclass of ActiveRecord can declare itself abstract by setting self.abstract_class = true. This tells ActiveRecord that it shouldn’t look for a table to go with that class.

I Like Stuff that Finally Works

Armed with this information I finally landed on a solution that works in Rails 3.2. As you can see, 3.2 is much less flexible than 3.1 about how you define your class structure to talk to external databases. Whereas 3.1 had several techniques that would work, as far as I know the following is the only way to make it work in 3.2:

  1. Make a common base class for all models that need to talk to a non-default database.
  2. Tell ActiveRecord that this base class is abstract.
  3. Establish the connection in the base class.

So here’s our final code:

class NasaTable < ActiveRecord::Base
  self.abstract_class = true
  establish_connection "nasa_#{Rails.env}"
end

class Astronaut < NasaTable
  has_many :missions
  has_many :shuttles, through: :missions
end

class Shuttle < NasaTable
  has_many :missions
  has_many :astronauts, through: :missions
end

class Mission < NasaTable
  belongs_to :astronaut
  belongs_to :shuttle
end

# test
shuttle = Shuttle.create name: "Endeavor"
shuttle.astronauts << Astronaut.create(name: "Mark Kelly")
assert_equal 1, shuttle.reload.astronauts.count # IT WORKS

A Side Note About Connection Pools

It would be nice to have the flexibility that 3.1 had. But as long as there is a reasonable solution, I’m happy. I should mention, however, that if you call establish_connection multiple times with the same connection key (e.g. the old way where each table calls establish_connection), you end up creating multiple connection pools to the same database. This seems like a problem, as Sam Saffron has pointed out. If a single app talks to a single database through multiple connections, the best way to manage those connections is via a single pool–not multiple pools that don’t know about each other.

If you stick with the method I described above, where only one base class establishes a connection to each database, you can avoid this problem.

Astronaut

You Should Update One Gem at a Time with Bundler. Here’s How.

[Update: added example of updating the sextant gem, which causes Rails to be updated as well.]

Hey Ruby developers,

When you run bundle update to update your gems, it updates all of them at once. If your app stops working or your tests start failing, it can be pretty hard to figure out which gem update broke it.

There are a couple of solutions I’ve seen people use to solve this. Neither of them is that great:

  1. Lock the versions numbers in your Gemfile. But hey, that’s a pain and it’s what Gemfile.lock is for. Locking the version numbers in the Gemfile should be the exception, not the rule.
  2. Run bundle update gemname.

You might think bundle update gemname would just update that gem. But no, it also updates the gem’s dependencies—whether they have to be updated or not.  In fact, updating a third party gem can even upgrade you to a new version of Rails behind your back.

Here’s what the Bundler doc says about bundle update gemname:

UPDATING A LIST OF GEMS

Sometimes, you want to update a single gem in the Gemfile(5), and leave the rest of the gems that you specified locked to the versions in the Gemfile.lock.

For instance, in the scenario above, imagine that nokogiri releases version 1.4.4, and you want to update it without updating Rails and all of its dependencies. To do this, run bundle update nokogiri.

Bundler will update nokogiri and any of its dependencies, but leave alone Rails and its dependencies.

Yeah, sure, that sounds nice. But read that last sentence again: “Bundler will update nokogiri and any of its dependencies.” Well, heck. Some gems depend on a ton of other gems. And why not? Nothing wrong with that. And it makes sense to update the dependencies if something new is required for the update to work. But Bundler updates them no matter what. And now you’re back to the problem I stated at the beginning: even if you intend to update only a single gem, you still end up updating a whole boatload of gems. So when your app breaks or your tests fail, it takes a lot of time to figure out why.

Want an example of an unexpected side-effect of bundle update? I have a good one. Let’s say you’ve installed the sextant gem into your Rails app so you can see your Rails routes in development mode by navigating to /rails/routes. (It saves time compared to rake routes since the environment is already loaded.) In this example you are on Rails 3.2.2 and sextant 0.1.2. Now you run bundle update sextant to update to 0.1.3. Do you know what you just did? You upgraded Rails from 3.2.2 to 3.2.6. I don’t know about you, but I don’t like having my version of Rails updated just because I got the latest version of some little helpful gem.

When writing this blog post I tried a few scenarios. I found something else interesting:

With bundle update gemnameeven if there is no newer version of that gem, it will still update everything the gem depends on.

Here’s an example. My app has version 0.3.4 of haml-rails, which at the moment is the newest version. I run:

bundle update haml-rails

After that, git diff informs me that my Gemfile.lock now has newer versions of the journey, json, multi_json, and sprockets gems. Even though it didn’t find an update to haml-rails.

The Solution: bundle update ––source gemname

Bundler has a solution, but in my opinion it’s hard to understand the documentation.

Here’s what you do:

bundle update ––source gemname

I started diving into Bundler’s code and specs to see exactly what this does but it was taking more time than I wanted to spend. But I’ve been using this for more than a year and it works great. I recommend this be your default way to update a gem. If it doesn’t work due to a dependency conflict with other gems then you can always fall back on bundle update gemname.

As far as I can tell, using ––source is the equivalent of the following, but without all the work and headache:

  1. Specifying version numbers for everything in your Gemfile.
  2. When you want to update a gem, running gem list -r gemname to find out its latest version number.
  3. Changing the version number in your Gemfile for just that one gem.
  4. Running bundle install.
If you look at bundle update‘s documentation for ––source, it doesn’t help much. Here’s what it says:

OPTIONS

––source=<name>

The name of a :git or :path source used in the Gemfile(5). For instance, with a :git source of http://github.com/rails/rails.git, you would call bundle update ––source rails

By the way, the bundle update documentation does mention conservatively updating dependencies. Here is what it has to say: “For more information, see the CONSERVATIVE UPDATING section of bundle install(1) bundle-install.1.html.” The bundle install section on conservative updating does indeed describe how to update dependencies conservatively. However, this section assumes you are specifying version numbers in your Gemfile. As I mentioned above, I prefer to do that only as an exception.

See ya.

How to Find a Record in ActiveRecord Using either an ID Or an Object

Have you ever written written code in an ActiveRecord model where you wanted the caller to be able to pass in either an object or an id?

In this example you want to know if a user has read a post. Your join table, readings, tells you which users have read each post.

class Post
  has_many :readings

  def read_by?(user_or_id)
    readings.where(:id =>
                     Fixnum === user_or_id ?
                     user_or_id :
                     user_or_id.id).exists?
  end
end

Good news: you don’t have to go through all that. ActiveRecord checks for you if the object is a number or a model. You can simplify the code quite a bit.

In this rewritten version the user parameter of the read_by? method can be either a user object or a user id:

class Post
  has_many :readings

  def read_by?(user)
    readings.where(:id => user).exists?
  end
end

19-Minute Video: CoffeeScript for Rubyists

If you’re a Ruby programmer and want a quick little intro to CoffeeScript so you can decide whether you might want to use it, check out the 19-minute talk I gave last week at a really fun Code Social meetup at RocketSpace in San Francisco. The talk was “CoffeeScript for Rubyists.”

Abstract

Is CoffeeScript really so great? Why use it instead of good ol’ JavaScript? Which of my favorite syntax goodies does it steal from Ruby? It looks Pythony with all that significant whitespace. How can I use it in my pre-3.1 Rails project? How do I convert my legacy JavaScript? Why is Internet Explorer no good at exploring the Internet? Brian Morearty answers most of these questions. He’s a Ruby aficionado who has used CoffeeScript for his client-side coding for a few months. In this talk he does a quick demo of how to install CoffeeScript, convert your JavaScript to CoffeeScript, and include it in a pre-Rails-3.1 application. But most of the talk is on details of the language, including stuff it stole from Ruby that make it just dang fun for a Rubyist to program in CoffeeScript. And he even covers one thing that is *gasp* better than Ruby.

Slides

Here are the slides for this CoffeeScript talk.

Video

And here’s the video:

Use Spin for Faster Test Iterations

RAILS TESTS - Y U NO EVEN START YET?!

Do you ever re-run the same Rails test file over & over while working on a feature and trying to “make it green?” Change the code, run the test, change the code, run the test, etc. (I’m talking about when you want to re-run a specific test, not using guard to autodetect which tests to run.)

When you do that you have to wait a long time for the Rails environment and your app’s initializers to load. You pay this price every time you re-run the test—even if you’re not changing your initializers. I get ants in my pants sitting around waiting for the environment to load.

I just learned about a new gem that doesn’t require any changes to your tests and that speeds up this test-code-test-code cycle by only loading your environment once: it’s called spin.

https://github.com/jstorimer/spin

Basically you do this:

  • In one terminal window type spin serve. This launches the spin server, which waits for commands over a socket.
  • In another terminal, when you want to run the tests in a single file, type spin push path/to/testfile.rb
  • You can push multiple filenames at once if you like.
  • One limitation: it does not let you use the :linenum syntax that rspec uses to run just one test in a file.

That’s it. I tried it on a test file that takes 8 seconds (after everything has been loaded). Total time to load and run this file went down from 26 seconds to 13 seconds when I used spin.

I looked at the source. It’s short and simple. Here’s how it works:

  • spin serve preloads your app’s config/application.rb.
  • Then it waits for commands on a socket.
  • When a command comes in it forks a new process and runs tests in the fork. The fork doesn’t have to reload the Rails environment or initializers because they’re already loaded.
  • When done, the fork just exits and spin is ready for a new command.

Remember that if you do change your initializers or anything else that is loaded by application.rb you should restart the spin server. Another time you may want to restart it: after checking out a different branch in git.

Safe and easy. Faster tests. What could be better?

How to Set a Time Zone for Each Request in Rails

The Railscast on Time Zones has some sample code that lets you set a thread-local, per-request time zone with a before_filter:

# controllers/application.rb
  before_filter :set_user_time_zone

  private

  def set_user_time_zone
    Time.zone = current_user.time_zone if logged_in?
  end

Problem is, the current user’s time zone will leak across to the next request on the same thread. If the next one is by a logged-out user, all times displayed on that next request will show in the first user’s time zone.

To prevent this, use an around_filter:

  around_filter :set_time_zone

  private

  def set_time_zone
    old_time_zone = Time.zone
    Time.zone = current_user.time_zone if logged_in?
    yield
  ensure
    Time.zone = old_time_zone
  end

You might be tempted to combine the first two lines of set_time_zone into one line with the comma assignment syntax and add “if logged_in?” to the one line in the ensure clause. Don’t do it. If you did that, the user’s time zone would leak out to the next request when the user logs out.

I’ve submitted a Rails patch to use this method in the sample code for the Time.zone= docs.

How to fix Ruby error: Unsupported digest algorithm (sha256).

This is a note to myself because this has happened to me more than once. I’m posting it publicly in case it helps others, too.

This is for people on a Mac, using rvm and homebrew.

I ran across this with the very nice Sucker gem, which lets you easily access the Amazon Product Advertising API. Amazon requires SHA-256 in its API calls, which is where my trouble began.

If your Ruby app got this error message in openssl/digest.rb:55:

Unsupported digest algorithm (sha256).

it’s because when you installed (compiled) Ruby, you linked in an older version of the openssl library.

I Like Stuff that Finally Worked

Here’s how I fixed it:

brew install openssl
rvm remove 1.8.7
rvm install 1.8.7 --with-openssl-dir=/usr/local/Cellar/openssl/0.9.8o/

To test it, run this in the Terminal:

ruby -ropenssl -e 'p OpenSSL::Digest::Digest.new("sha256")'

If you don’t get an error message, it worked.

Things That Didn’t Work

Installing and building openssl from source (openssl.org) did not work.

Installing the openssl rvm package and removing+reinstalling ruby did not work.

What finally worked was the steps above. Woo hoo!

By the way, I did not have to upgrade to Snow Leopard.

What about Ruby 1.9.2?

I still haven’t gotten it working in Ruby 1.9.2. I run this:


rvm install 1.9.2 --with-openssl-dir=/usr/local/Cellar/openssl/0.9.8o/

and I get this output:


ruby-1.9.2-p136 - #fetching
ruby-1.9.2-p136 - #extracted to /Users/Brian/.rvm/src/ruby-1.9.2-p136 (already extracted)
ruby-1.9.2-p136 - #configuring
ruby-1.9.2-p136 - #compiling
Error running 'make ', please read /Users/Brian/.rvm/log/ruby-1.9.2-p136/make.log
There has been an error while running make. Halting the installation.

So I go look in make.log and I see this at the end:


Generating RDoc documentation
./miniruby -I./lib -I.ext/common -I./- -r./ext/purelib.rb  ./tool/runruby.rb --extout=.ext  -- "./bin/rdoc" --no-force-update --all --ri --op ".ext/rdoc"  "."
/Users/Brian/.rvm/gems/ruby-1.8.7-p330/gems/rdoc-3.4/lib/rdoc/rdoc.rb:79: warning: already initialized constant GENERATORS
uh-oh! RDoc had a problem:
undefined method `coverage_report' for #<RDoc::Options:0x7841a0>

Does anyone know how to fix it?

Quick and Dirty Performance Profiling in Ruby

Occasionally I read Rails source code to learn/re-learn what it’s capable of.

Want to do some quick and dirty profiling to see how long some Ruby code takes? Do this in irb or in a Ruby project:

require 'rubygems'
require 'active_support/core_ext/benchmark'

puts Benchmark.ms do
   # put your code here
end

The output is how long in milliseconds the code took to run.

This requires ActiveSupport but does not require all of Rails. If you don’t have ActiveSupport, install it with gem install activesupport.