Bundler & Formtastic: undefined link_to
We had a bizarre bug pop up recently with while running Bundler 0.9.11, Rails 2.3.5 and Formtastic 0.9.7.
I say bizarre because everything was working fine until we removed Clearance. Then our standard Rails form helpers stopped working.
Here are the steps we took to make it work again:
Remove the monkey patch that seems to be ubiquitous for running Bundler in Rails 2.3.5:
# Delete all this
class Rails::Boot
def run
load_initializer
extend_environment
Rails::Initializer.run(:set_load_path)
end
def extend_environment
Rails::Initializer.class_eval do
old_load = instance_method(:load_environment)
define_method(:load_environment) do
Bundler.require
old_load.bind(self).call
end
end
end
end
Modify environment.rb to load the Bundler env
require File.join(File.dirname(__FILE__), 'boot') class MyAppInitializer < Rails::Initializer def load_gems super Bundler.require end endMyAppInitializer.run do |config| config.logger = Logger.new(config.log_path) config.time_zone = 'UTC' end
Ruby Tidbits: Spork your Cucumber
This is a continuation of last week’s post. Not long after Tim Harper released Spork for RSpec, the Cucumber team announced support for Spork in Cucumber. If this sounds like some kind of dining meme, just let me show you how much of a picnic this is to use.
Since the last blog post, Spork 0.5.7 has been released, so I’ll be using that version here. Cucumber is at version 0.3.11.
First, let’s bootstrap Cucumber
ruby script/generate cucumber
Time to generate some features.
script/generate feature Spoon color:string size:string
We can make our features pass pretty easily for this example.
script/generate rspec_scaffold Spoon color:string size:string
Don’t forget to migrate
rake db:migrate
Now start spork for cucumber
spork cuc
And run the features
rake features
Now we’re not going to see much here since this project is so small, but I did time the run on these.
Without Spork
time rake features
real 0m3.296s
user 0m2.456s
sys 0m0.756s
With Spork:
time rake features
real 0m1.914s
user 0m1.093s
sys 0m0.298s
I would love to see some real world stats on this on somebody’s cucumber suite. If you want help getting this going on your long running suite, let me know and I’ll lend a hand in exchange for getting some timing results.
Ruby Tidbits: Spork
Last week Tim Harper announced Spork, which is billed as a better RSpec DRb server. What does that mean, and why should I care?
RSpec of course is a Behavior Driven Development framework for Ruby. DRb is a distributed object system for Ruby, and it ships with the standard library.
As a Rails code base gets larger, you can start to see app initialization times increase. In production, this isn’t a big problem, since you aren’t frequently starting your app. However, when you are involved in a rapid development/test cycle this can become a nuisance when you start to find yourself waiting for your app to initialize to run your tests.
Spork aims to tackle this problem by only taking that initialization hit once. It starts up the application environment, and then listens over DRb. Then, RSpec can connect to that DRb server and run specs inside that process, skipping the initialization. Furthermore, before running the specs, Spork will fork itself, which is a relatively inexpensive call on POSIX1 systems. Then, when the specs are done running, this process can just go away, and we don’t have to worry about object pollution when running specs again later.
Let’s see just how easy it is to get going with Spork.
My environment for this tidbit includes:
- Mac OS X 10.5.7
- Rails 2.3.2
- RSpec 1.2.6
- The Spork I am installing is version 0.5.6
Install Spork from Ruby gems.
sudo gem install spork
Create (use an existing) Rails project
rails crappy_spoon
Edit config/environments/test.rb. And add the following lines to tell Rails we are using RSpec.
config.gem "rspec", :lib => false
config.gem "rspec-rails", :lib => false
Bootstrap the RSpec environment.
script/generate rspec
I’m going to use scaffolding just to get some specs to try things out with. (Don’t forget to migrate)
script/generate rspec_scaffold Fork
rake db:migrate
I have a little benchmark script that will run a command an number of times and print out the results. Running rake to run these specs 5 times gives:
| user | system | total | real | |
| 0.000000 | 0.000000 | 5.350000 | 6.364407 | |
| 0.000000 | 0.000000 | 5.300000 | 5.648598 | |
| 0.000000 | 0.000000 | 5.320000 | 5.694012 | |
| 0.000000 | 0.000000 | 5.300000 | 5.610330 | |
| 0.000000 | 0.000000 | 5.350000 | 5.824451 | |
| >total: | 0.000000 | 0.000000 | 26.620000 | 29.141798 |
| >avg: | 0.000000 | 0.000000 | 5.324000 | 5.828360 |
So on average on my machine I had to wait 5.8 seconds to run all my specs.
Let’s enable Spork and try it again.
spork --bootstrap
When that’s done, it prints out a message for us.
Done. Edit /Users/redinger/workspaces/rubyrx/crappy_spoon/spec/spec_helper.rb now with your favorite text editor and follow the instructions.
So, let’s go do that. I moved everything into the prefork section for this example. Here’s my final spec_helper.rb:
require 'rubygems'
require 'spork'
Spork.prefork do
ENV["RAILS_ENV"] ||= 'test'
require File.dirname(__FILE__) + "/../config/environment"
require 'spec/autorun'
require 'spec/rails'
Spec::Runner.configure do |config|
config.use_transactional_fixtures = true
config.use_instantiated_fixtures = false
config.fixture_path = RAILS_ROOT + '/spec/fixtures/'
end
end
Spork.each_run do
end
Then, edit spec.opts to enable drb:
spec.opts --drb
Load up spork
spork
Rerunning the benchmark:
| user | system | total | real | |
| 0.000000 | 0.000000 | 2.220000 | 3.100511 | |
| 0.000000 | 0.000000 | 2.210000 | 3.147859 | |
| 0.000000 | 0.010000 | 2.230000 | 3.057866 | |
| 0.000000 | 0.000000 | 2.190000 | 2.919749 | |
| 0.000000 | 0.000000 | 2.190000 | 2.864102 | |
| >total: | 0.000000 | 0.010000 | 11.040000 | 15.090087 |
| >avg: | 0.000000 | 0.002000 | 2.208000 | 3.018017 |
And we are now down to an average of 3 seconds. Obviously this is with a bare bones app, so we don’t see the real performance savings that we would with a real world app. But, just for the sake of argument, let’s say someone accidentally added a sleep 5 to the init process (simulating an additional 5 second app initialization time).
Rerunning without Spork running (it’s worth pointing out here if you run rspec without having a Spork process running, the specs will just revert to running the old way, printing out a message notifying you there is no server running.):
| user | system | total | real | |
| 0.000000 | 0.000000 | 6.150000 | 18.199735 | |
| 0.000000 | 0.000000 | 5.040000 | 10.131084 | |
| 0.000000 | 0.000000 | 5.040000 | 10.217521 | |
| 0.000000 | 0.000000 | 5.060000 | 10.121561 | |
| 0.000000 | 0.000000 | 5.020000 | 10.150404 | |
| >total: | 0.000000 | 0.000000 | 26.310000 | 58.820305 |
| >avg: | 0.000000 | 0.000000 | 5.262000 | 11.764061 |
That causes the extra time to be seen for each running of the specs. Under spork, which takes an additional 5 seconds to start up the Spork server:
| user | system | total | real | |
| 0.000000 | 0.000000 | 2.090000 | 2.722946 | |
| 0.000000 | 0.000000 | 2.080000 | 2.661724 | |
| 0.000000 | 0.000000 | 2.110000 | 2.731659 | |
| 0.000000 | 0.000000 | 2.080000 | 2.665148 | |
| 0.000000 | 0.010000 | 2.100000 | 2.647866 | |
| >total: | 0.000000 | 0.010000 | 10.460000 | 13.429343 |
| >avg: | 0.000000 | 0.002000 | 2.092000 | 2.685869 |
No extra time. (Technically, less time, but we’ll count that as margin of error.)
One final thing to point out, if you just run spork -d it will run diagnostic mode, which will list which files are being preloaded, and don’t get reloaded each time the specs are run.
Hopefully if you are using RSpec in your Rails project you can see how using spork can immediately benefit you.
1 Right, I said POSIX, so Windows users will need to pursue a different solution for now.
Default Routes and Rails Engines don't mix
Of course we’ve known for a while to not use default routes in combination with restful routes. However, there is a hidden danger when dealing with Engines. I was doing what should have been a quick experiment with an Engine in Rails 2.3. So, I generated a default app.
rails cereal rails fruits cd cereal script/generate scaffold cornflake
Then I follow the incantation to get my fruits engine into my cereal app. Part of that process involves copying over the routes.rb file. However, by default, that has these unfortunate routes defined already:
map.connect ':controller/:action/:id' map.connect ':controller/:action/:id.:format'
Now, I hit my app at /cornflakes/new, hit the ‘Create’ button, and it posts to … my ‘index’ action?? What’s up with that? Well, it took a while, but then I remembered that default route. I’m assuming that the plugin routes get processed first, and that default route is getting installed before my resourceful route. Meaning, nothing in my app’s routes.rb file is going to get recognized. No corn flakes, no lucky charms, nothing.
Removing the offending lines set the world back to normal. Time to eat.
Passenger, nginx & Leopard development
If you’re wondering if you can still develop on your Mac using Passenger along with the nginx config – the answer is of course you can!
First, follow the installation instructions.
Then you’ll need to edit your /etc/hosts file to tell your host about the virtual domain. (This is only necessary I assume until the fantastic Passenger Preference Pane is updated to work with nginx)
127.0.0.1 localhost my_facebook_killer.local
Finally, update your nginx.conf, which is pretty much the same as the Passenger installation instructions, with one extra line for development.
server {
listen 80;
server_name my_facebook_killer.local;
root /path/to/your/rails/app/public;
passenger_enabled on;
rails_env development; # This line tells passenger to start in development mode.
}
Now restart nginx and you should be able to test your app by hitting http://my_facebook_killer.local in your browser

