How to make roo/google-spreadsheet-ruby work with rails

I use Roo in my Rails application to parse Excel spreadsheets that are uploaded by the user. It’s a nice plugin and makes it very easy to do what would otherwise be a difficult task (especially as it’s largely file-format agnostic, although I’m not using this functionality). However, after upgrading to 1.9.1 it broke rake:

** Invoke db:seed (first_time)
** Invoke environment (first_time)
** Execute environment
** Execute db:seed
rake aborted!
uninitialized constant ActiveSupport::Multibyte::Chars::Encoding
/Library/Ruby/Gems/1.8/gems/activesupport-2.3.4/lib/active_support/dependencies.rb:105:in `const_missing'
/Library/Ruby/Gems/1.8/gems/activesupport-2.3.4/lib/active_support/multibyte/chars.rb:86:in `initialize'
/Library/Ruby/Gems/1.8/gems/activesupport-2.3.4/lib/active_support/core_ext/string/multibyte.rb:44:in `new'
/Library/Ruby/Gems/1.8/gems/activesupport-2.3.4/lib/active_support/core_ext/string/multibyte.rb:44:in `mb_chars'
/Library/Ruby/Gems/1.8/gems/activerecord-2.3.4/lib/active_record/validations.rb:798:in `validates_uniqueness_of'
/Library/Ruby/Gems/1.8/gems/activerecord-2.3.4/lib/active_record/validations.rb:468:in `validates_each'
/Library/Ruby/Gems/1.8/gems/activerecord-2.3.4/lib/active_record/validations.rb:465:in `each'
/Library/Ruby/Gems/1.8/gems/activerecord-2.3.4/lib/active_record/validations.rb:465:in `validates_each'
/Library/Ruby/Gems/1.8/gems/activesupport-2.3.4/lib/active_support/callbacks.rb:182:in `call'
/Library/Ruby/Gems/1.8/gems/activesupport-2.3.4/lib/active_support/callbacks.rb:182:in `evaluate_method'
/Library/Ruby/Gems/1.8/gems/activesupport-2.3.4/lib/active_support/callbacks.rb:166:in `call'
/Library/Ruby/Gems/1.8/gems/activesupport-2.3.4/lib/active_support/callbacks.rb:90:in `run'
/Library/Ruby/Gems/1.8/gems/activesupport-2.3.4/lib/active_support/callbacks.rb:90:in `each'
/Library/Ruby/Gems/1.8/gems/activesupport-2.3.4/lib/active_support/callbacks.rb:90:in `send'
/Library/Ruby/Gems/1.8/gems/activesupport-2.3.4/lib/active_support/callbacks.rb:90:in `run'
/Library/Ruby/Gems/1.8/gems/activesupport-2.3.4/lib/active_support/callbacks.rb:276:in `run_callbacks'
/Library/Ruby/Gems/1.8/gems/activerecord-2.3.4/lib/active_record/validations.rb:1098:in `valid_without_callbacks?'
/Library/Ruby/Gems/1.8/gems/activerecord-2.3.4/lib/active_record/callbacks.rb:315:in `valid_without_lifecycles?'
/Library/Ruby/Gems/1.8/gems/hobo-0.8.10/lib/hobo/lifecycles.rb:67:in `valid?'
/Library/Ruby/Gems/1.8/gems/activerecord-2.3.4/lib/active_record/validations.rb:1077:in `save_without_dirty'
/Library/Ruby/Gems/1.8/gems/activerecord-2.3.4/lib/active_record/dirty.rb:79:in `save_without_transactions'
/Library/Ruby/Gems/1.8/gems/activerecord-2.3.4/lib/active_record/transactions.rb:229:in `send'
/Library/Ruby/Gems/1.8/gems/activerecord-2.3.4/lib/active_record/transactions.rb:229:in `with_transaction_returning_status'
/Library/Ruby/Gems/1.8/gems/activerecord-2.3.4/lib/active_record/connection_adapters/abstract/database_statements.rb:136:in `transaction'
/Library/Ruby/Gems/1.8/gems/activerecord-2.3.4/lib/active_record/transactions.rb:182:in `transaction'
/Library/Ruby/Gems/1.8/gems/activerecord-2.3.4/lib/active_record/transactions.rb:228:in `with_transaction_returning_status'
/Library/Ruby/Gems/1.8/gems/activerecord-2.3.4/lib/active_record/transactions.rb:196:in `save'
/Library/Ruby/Gems/1.8/gems/activerecord-2.3.4/lib/active_record/transactions.rb:208:in `rollback_active_record_state!'
/Library/Ruby/Gems/1.8/gems/activerecord-2.3.4/lib/active_record/transactions.rb:196:in `save'
/Library/Ruby/Gems/1.8/gems/activerecord-2.3.4/lib/active_record/base.rb:723:in `create'
/Users/iainbeeston/Documents/Programs/Ruby/inspect/db/seeds.rb:9
/Library/Ruby/Gems/1.8/gems/activesupport-2.3.4/lib/active_support/dependencies.rb:145:in `load_without_new_constant_marking'
/Library/Ruby/Gems/1.8/gems/activesupport-2.3.4/lib/active_support/dependencies.rb:145:in `load'
/Library/Ruby/Gems/1.8/gems/activesupport-2.3.4/lib/active_support/dependencies.rb:521:in `new_constants_in'
/Library/Ruby/Gems/1.8/gems/activesupport-2.3.4/lib/active_support/dependencies.rb:145:in `load'
/Library/Ruby/Gems/1.8/gems/rails-2.3.4/lib/tasks/databases.rake:215
/Library/Ruby/Gems/1.8/gems/rake-0.8.7/lib/rake.rb:636:in `call'
/Library/Ruby/Gems/1.8/gems/rake-0.8.7/lib/rake.rb:636:in `execute'
/Library/Ruby/Gems/1.8/gems/rake-0.8.7/lib/rake.rb:631:in `each'
/Library/Ruby/Gems/1.8/gems/rake-0.8.7/lib/rake.rb:631:in `execute'
/Library/Ruby/Gems/1.8/gems/rake-0.8.7/lib/rake.rb:597:in `invoke_with_call_chain'
/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/1.8/monitor.rb:242:in `synchronize'
/Library/Ruby/Gems/1.8/gems/rake-0.8.7/lib/rake.rb:590:in `invoke_with_call_chain'
/Library/Ruby/Gems/1.8/gems/rake-0.8.7/lib/rake.rb:583:in `invoke'
/Library/Ruby/Gems/1.8/gems/rake-0.8.7/lib/rake.rb:2051:in `invoke_task'
/Library/Ruby/Gems/1.8/gems/rake-0.8.7/lib/rake.rb:2029:in `top_level'
/Library/Ruby/Gems/1.8/gems/rake-0.8.7/lib/rake.rb:2029:in `each'
/Library/Ruby/Gems/1.8/gems/rake-0.8.7/lib/rake.rb:2029:in `top_level'
/Library/Ruby/Gems/1.8/gems/rake-0.8.7/lib/rake.rb:2068:in `standard_exception_handling'
/Library/Ruby/Gems/1.8/gems/rake-0.8.7/lib/rake.rb:2023:in `top_level'
/Library/Ruby/Gems/1.8/gems/rake-0.8.7/lib/rake.rb:2001:in `run'
/Library/Ruby/Gems/1.8/gems/rake-0.8.7/lib/rake.rb:2068:in `standard_exception_handling'
/Library/Ruby/Gems/1.8/gems/rake-0.8.7/lib/rake.rb:1998:in `run'
/Library/Ruby/Gems/1.8/gems/rake-0.8.7/bin/rake:31
/usr/bin/rake:19:in `load'
/usr/bin/rake:19

What’s more it also broke Rapid (the templating engine in Hobo).

After a little investigation it turned out that in both cases it was trying to use Encoding::UTF_8, but this is not defined in Ruby 1.8.

It turns out that after updating google-spreadsheet-ruby (a dependency of roo) to version 0.0.6 this was defining String.force_encoding() for Ruby 1.8 (normally this method is only in Ruby 1.9). Rails uses this method to check if the version of Ruby being used is 1.8 or 1.9, so defining it just confuses it and was leading to the crashes.

Solution:

If you’re using Ruby 1.8 and you don’t need google-spreadsheets-ruby, just undefine String.force_encoding():

class String
        if '1.9'.respond_to?(:force_encoding)
                undef :force_encoding
        end
end

If you do need to use that gem then a more complex solution is needed.

Note

I’ve been informed by the author that the fix has been committed to edge and will be released in the next version (presumably 0.0.7).

Advertisements

About this entry