Ruby Update Breaking old Rails Apps

no comments

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.

Thunderbird Copy to Sent IMAP Connection Error

3 comments

This article applies to: Thunderbird v.2.0.0.9 and a few previous versions and may very well be applicable in the future.

The Solution

I’m assuming you want the solution and not the explanation. If you really do want the explanation, scroll down and come back!

After I set up my own IMAP server for my e-mail, I began to get error messages from Thunderbird: “Error copying message to sent folder. Retry? OK.” Rather than change my Postfix server (which was advised against by the documentation), I looked for a client-side solution. Retrying is a crap-shoot. Sometimes it copies, but most of the time it just sits there after informing you that:

Unable to connect to your IMAP server. You may have exceeded the maximum number of connections to this server. If so, use the Advanced IMAP Server Settings Dialog to reduce the number of cached connections.

Advanced IMAP Server Settings Dialog? I’ve never heard of that before. Let’s see what about:config has to say. You can find it in Tools→Options… on Windows, or Edit→Options… on other platforms. Once you see the dialog, hit the “Advanced” icon at the top right, then hit the “General” tab in the area below it. You’ll see “Config Editor…”.

I tried setting: mail.imap.max_cached_connections from 5, to 1, to 0. No value fixes it.

I then noticed: mail.server.server2.max_cached_connections And not just that one (I have several IMAP accounts). There were a few others as well. Setting these to 1 HAS solved my problem.

Just make sure all your: mail.server.server*N*.max_cached_connections = 1

Now, had I listened to the error message from the start, I would have gone to the account settings for each. Right click on the IMAP account and select properties. Then goes to server settings. You’ll notice an “Advanced” button. Sure enough, you see the text field for the number of cached connections. Of course, if you want to change them all at once, you can use the Config Editor.

Remember, restart Thunderbird for the changes to take effect. Don’t expect miracles until after you’ve relaunched.

The Explanation

IMAP connection caching? Yes, when Thunderbird checks your e-mail over IMAP, it starts up a TCP connection. That’s a 3-way handshake.

  1. Hello Server!
  2. Hello Client!
  3. Hello again Server! (I got your hello)

3 Hello’s = 3 way handshake. OK OK, yes, this is a gross oversimplification. None-the-less, this handshake sequence is considered slow and “expensive.” So instead of saying good-bye after getting your mail, the client will say, “I’ll be back, so leave the line open.” Sounds good, but most servers have limited resources. Once the maximum number of connections is reached, it won’t accept any more. That’s what is happening with Thunderbird here. It’s being told that there is no more room.

So, what limited resource am I talking about? Well, those connections take up memory, especially the secure ones. SSL adds the overhead of a new shared secret (passphrase). That’s not too bad, but it’s more than storing the usual, unencrypted nothing. Even if you don’t use SSL, each connection uses a new port. Every computer has 65535 ports. Depending on the system, approximately 1000 of them are reserved for system calls. The other 64,000 and change are shared among all the services provided by the server. And, yup, you guessed it, each connection uses up a port.

May not seem like a big deal. But say, you have an account. Thunderbird caches 5 connections by default. If you have 5 folders, it will use all 5 connections and cache them. If your e-mail is on a dedicated machine: 64,535/5 = 12,907. Only 13 thousand users can check their mail (if they all have 5 or more folders). If you have a big company, this would be bad if the CEO or POB (pointy haired boss) can’t check his or her e-mail. Most servers will limit you (as did mine and probably yours if you’re reading this article to solve your problem) to 4 connections from the same IP address. While it helps solve the connection volume problem, Thunderbird gets confused.

See, if you need a new connection on the same account, thunderbird will use any active ones. But if you have multiple accounts, Thunderbird assumes the connections are independent. Apparently, this is a mistake.

An Expert Fix

I suggest that Thunderbird take note of refused connections and give up active connections from other accounts if they resolve to the same server. That will expand the already automatic connection cycling feature among connections on the same account to connections on the same client.