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
bundle
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:
/Users/mhartl/.rvm/gems/ruby-2.0.0-p0@rails_4_0_rc1/gems/activerecord-
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/
F
Failures:
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
end
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
end
end
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).