Rails 4.0 Release Candidate 1

May 10, 2013 • posted by Michael Hartl

Update: Steve Klabnik has solved the problem discussed in the post below by noting that the latest version of the rspec-rails gem (2.13.1) has fixes specific to Rails 4.0. After upgrading the Gemfile to use this version, I have confirmed that the issue described in the post is fixed. Thanks, Steve!

The first Rails 4.0 release candidate, Rails 4.0 RC1, is now available. Unfortunately, although the Rails Tutorial sample app appears to run fine under the RC, a large number of tests fail. Most of the failing tests appear to be related to the test database not being rolled back properly. I’m posting the details here both to solicit assistance and to serve as a reference for the issue I’ve filed on the Rails issue tracker at GitHub. This issue is currently the main obstacle blocking the preparation of the Rails 4.0–compatible version of the Ruby on Rails Tutorial book.

Isolating the issue

To isolate the issue, I’ve prepared a minimial failing app. To reproduce the error I’m seeing, first clone it from GitHub:

git clone https://github.com/mhartl/failing_app_rails_4_0_rc1.git

Then install the gems and migrate the database:

cd failing_app_rails_4_0_rc1
rvm use 2.0.0@rails_4_0_rc1 --create
gem install bundler
rake db:migrate

Preparing the test database

So far, so good. The first problem comes from trying to run the tests after preparing the test database:

rake db:test:prepare
rspec spec/

Unfortunately, this doesn’t work. Instead, I get an error:

4.0.0.rc1/lib/active_record/migration.rb:376:in `check_pending!': 
Migrations are pending; run 'rake db:migrate RAILS_ENV=test' to resolve 
this issue. (ActiveRecord::PendingMigrationError)

I have never had to run rake db:migrate RAILS_ENV=test in the course of normal Rails application development. To my knowledge, this should automatically be handled by

rake db:test:prepare

But to proceed I had to run it:

rake db:migrate RAILS_ENV=test

Passing test, then failing test

The test now passes:

$ rspec spec/

Finished in 0.03903 seconds
1 example, 0 failures

Unfortunately, running the test a second time produces an error:

$ rspec spec/


  1) User should save the user
     Failure/Error: expect { user.save! }.not_to raise_error
       expected no Exception, got #<ActiveRecord::RecordInvalid: Validation
       failed: Email has already been taken> with backtrace:
         # ./spec/models/user_spec.rb:6:in `block (3 levels) in <top (required)>'
         # ./spec/models/user_spec.rb:6:in `block (2 levels) in <top (required)>'
     # ./spec/models/user_spec.rb:6:in `block (2 levels) in <top (required)>'

Finished in 0.03405 seconds
1 example, 1 failure

Email uniqueness

If you look at the source code, you’ll see that the “app” is really just a User model that enforces email uniqueness:

# app/models/user.rb
class User < ActiveRecord::Base
  validates :email, uniqueness: true

The corrsponding test just tries to save the user:

# spec/models/user_spec.rb
require 'spec_helper'

describe User do
  let(:user) { User.new(email: "[email protected]") }
  it "should save the user" do
    expect { user.save! }.not_to raise_error

After excuting the test, Rails should roll back the test database, but instead it is persisting from invocation to invocation, resulting in a violation of the email uniqueness constraint the second time through.

Reproducing the error

We can reproduce the error by removing the test database, re-migrating, and running the test again (twice):

$ rm -f db/test.sqlite3 && rake db:migrate RAILS_ENV=test
$ rspec spec/
# test passes
$ rspec spec/
# test fails

Any help in solving this issue would be much appreciated (admin at railstutorial dot org).