PaperTrail + Sinatra strangeness

This is one of those Google-baiting posts that coders write for other coders in hopes of saving them hours of frustration. It's unlikely to be of interest to anybody else.

As we moved Profitably to Rails 3, we were having a strange problem upgrading PaperTrail. PaperTrail needs to be upgraded to 2.x for Rails 3, but as soon as we upgraded it, we couldn't even load the environment. The traceback we'd get looked like this:

$ ./script/rails runner "puts 'hello world'"
/Users/francis/.gem/gems/activerecord-3.0.7/lib/active_record/named_scope.rb:132:in `valid_scope_name?': private method `warn' called for nil:NilClass (NoMethodError)
  from /Users/francis/.gem/gems/activerecord-3.0.7/lib/active_record/named_scope.rb:102:in `scope'
  from /Users/francis/.gem/gems/paper_trail-2.5.0/lib/paper_trail/version.rb:18
  from /Users/francis/.gem/gems/activesupport-3.0.7/lib/active_support/dependencies.rb:239:in `require'
  from /Users/francis/.gem/gems/activesupport-3.0.7/lib/active_support/dependencies.rb:239:in `require'
  from /Users/francis/.gem/gems/activesupport-3.0.7/lib/active_support/dependencies.rb:225:in `load_dependency'
  from /Users/francis/.gem/gems/activesupport-3.0.7/lib/active_support/dependencies.rb:596:in `new_constants_in'
  from /Users/francis/.gem/gems/activesupport-3.0.7/lib/active_support/dependencies.rb:225:in `load_dependency'
  from /Users/francis/.gem/gems/activesupport-3.0.7/lib/active_support/dependencies.rb:239:in `require'
  from /Users/francis/.gem/gems/paper_trail-2.5.0/lib/paper_trail.rb:7
  from /Users/francis/.gem/gems/bundler-1.0.15/lib/bundler/runtime.rb:68:in `require'

If you're seeing this error, you may also have Sinatra in your Rails app for some strange reason (our strange reason is explained below). If that's the case, then the fix is to tweak your Gemfile with a require option:

gem 'sinatra', '1.0', :require => 'sinatra/base'

If the fix is simple, the actual cause was pretty gnarly. PaperTrail comes packaged with an ActiveRecord model called Version, with a scope called after. In ActiveRecord, the scope method will log a line if it's overwriting an existing method, though in this case ActiveRecord.logger isn't even defined yet, so you get a traceback from trying to call nil#after.

Why is Version.after defined? Because we're using Sinatra in our full-stack tests. Profitably supports authentication from a few external sources, and we got to the point where we wanted to test an external authentication source in combination with our Javascript and our Rails code. The best way we found to do that was to create a secondary server in Sinatra that our capybara test would spin up, for the purpose of simulating a POST from somebody else's website.

Sinatra, by default, writes a bunch of global methods like get, put, post, etc, which makes perfect sense if you're writing a quick Sinatra app, so you can do stuff like:

get '/hi' do
  "Hello World!"

Only problem being, in our case, that it also defines after, which is then defined on every Ruby object, including PaperTrail's Version class. (Yes, defining a method globally will define it on every single Ruby object, which is why you don't want to do it that often.)

Anyway, you can configure Sinatra not to create those methods globally, which is what the above Gemfile change will get you.

blog comments powered by Disqus
Tagged: ruby

« Previous post

Next post »