Ruby Update Breaking old Rails Apps
Jan
Background
Lately, I’ve been updating my Mac and Linux systems (AS I SHOULD!) and I’ve been getting errors for the passed few months from my Rails-based applications. They’ll be 500 errors (server error).
The Problem
It seems that a Ruby1.9 (from Ruby1.8) update has added the function “chars” to the core String class. Unfortunately, Rails prior to version 2 (I have not had this issue with newer, Rails 2 projects, I can only assume it’s not an issue: consider it unconfirmed) uses this method/attribute in a Rails ActiveSupport extension that allows you to slice up strings in an easier way.
Specifically, the ActiveSupport library assumes that the String class does NOT define the “chars” function. However, with Ruby1.9, it does. This leads to a conflict of types. Rails wants to use an attribute (as defined with ActiveSupport), Ruby1.9 is offering a method. The method wins and Ruby thinks the result of “chars” is an enumerator when it’s really expecting a String. Under Ruby 1.8, String included Enumerable as a mixin module. In 1.9, String no longer includes this.
The Rails team saw a need for the method chars and created one in activesupport/lib/active_support/core_ext/string/unicode.rb, then the Ruby core team added their own to the string class. Thus the conflict and thus the error.
The Solution
I picked this up from various websites reporting the same issue. They’re just not easy to find. You need to insert this code into the config/boot.rb file in the affected application. I put it at the top.
# Fix for ./script/../config/../config/../vendor/
#rails/activerecord/lib/../../activesupport/lib/
#active_support/core_ext/string/access.rb:43:in
# `first':NoMethodError: undefined method `[]' for
##<Enumerable::Enumerator:0x103767ec0>
unless '1.9'.respond_to?(:force_encoding)
String.class_eval do
begin
remove_method :chars
rescue NameError
# OK
end
end
end
# /Fix
It effectively removes the function “chars” from the String class that is added in from Ruby1.9. Hopefully, the Rails equivalent is the same and as or more secure.. But only does this if the String class has the method “force_encoding”. Why force_encoding? because it appeared in 1.9 along with “chars.” That’s the only link. So, should they remove “force_encoding” later, this fix won’t work any more.
Suggestions
Upgrade Rails to 2.0+ That should fix you up. Or avoid Ruby 1.9… I don’t recommend that though. They’ve isolated some of the core functionality into libraries. Ruby should have less of a memory footprint. I’d imagine there are security fixes .
It is also unfortunate that this situation occurred. I’m not sure how it can be avoided in the future. Things get updated. A little warning about them would be nice, however I’m actually amazed it hasn’t happened already. Kudos to the Rails/Ruby team.