This post originated from an RSS feed registered with Ruby Buzz
by Rick DeNatale.
Original Post: Making RSpec, Rake, and Bundler play well together
Feed Title: Talk Like A Duck
Feed URL: http://talklikeaduck.denhaven2.com/articles.atom
Feed Description: Musings on Ruby, Rails, and other topics by an experienced object technologist.
I'm working a project which uses RSpec, Bundler, and Rails 2.3.4.
The team has been struggling with the changes in gem management with Bundler. The "Old School" rails way to configure gems for different rails environments is to conditionally execute gem.configure based on the rails environment. Then use the rake:gems:install task to gem install the gems, one for each environment.
Bundler does things a bit differently. It uses groups to segregate gems by environment, so you name the gems needed for the test environment in a :test group. When you run bundle install, it installs all of the gems for all of the groups (unless you opt out of some groups. It uses the groups at run time, to selectively expose only gems applicable to the current environment.
This cause problems for things like the spec rake task. If you run
rake spec
without explicitly setting the Rails environment.
The way the spec rake task works is that it depends on a rails provided rake task called :environment, which 'boots' the rails environment, then the spec_helper file which each spec whould require, sets ENV['RAILS_ENV'] to 'test' if it's not already set, then it requires needed gem code, like 'spec/rails'.
In the old school approach this works, since those gems are installed and visible. With bundler, it fails since they won't be exposed, since the bundler environment got set up using the development environment, so gems in the :test group aren't available.
In an attempt to fix this, other members on the team were mixing things up, doing things like putting conditional tests of the rails environment in the Gemfile, and then running the bundle command with different overrides of the RAILS_ENV environment variable.
But that way lies madness.
This morning I worked out a solution which involves deferring setting up the bundle environment.
I needed to keep the spec task from running the environment task. The project was already using a variation of override_rake_task, so I added an override in a task within the lib directory:
override_task :specdoRake::Task["spec:original"].execute
end
The next step was to bootstrap the rails environment in spec_helper. To do this I started it with:
ENV["RAILS_ENV"] ||= 'test'RAILS_ROOT = "#{File.dirname(__FILE__)}/.."unlessdefined?(RAILS_ROOT)
environment_path = File.expand_path(File.join(RAILS_ROOT, 'config', 'environment'))
require(environment_path)
require 'spec/rails'#... any other needed requires
It's crucial to expand the path which ensures that the same string is used whenever the environment file is required. Before I did that I was having problems with the environment being required a second time, presumably for the second spec. If you have any code which patches anything using alias_method_chain, or a similar technique, loading that code a second time can cause infinite loops which can be mystifying.
So this seems to be working. I'll try to update if I find anything else, but in the meantime I hope some folks find it useful.
Original article writen by Rick DeNatale and published on Talk Like A Duck | direct link to this article | If you are reading this article elsewhere than Talk Like A Duck, it has been illegally reproduced and without proper authorization.