Why you can’t run Rails 2.3 applications on Ruby 1.9

The recent release of Rails 2.3.5 has fixed some Ruby 1.9 related bugs - which is nice. So I thought this is the right time to try porting an existing Rails 2.3 app to Ruby 1.9. Again, I was out of luck. The encoding problems present in Rails 2.3 are just unbearable. Let me show what I mean with a little example. We will build a little example app and use some special characters to see if things go wrong.

First, in order to set the default external encoding to UTF-8 for Ruby 1.9, we add this line to our .zshrc, .profile or whatever file is loaded by your shell:

export LANG=en_US.UTF-8

Then, we either need to open a new shell window or re-source the file:

source ~/.zshrc

After that, we can check if everything worked by running irb.

irb(main):004:0> Encoding.default_external
=> #<Encoding:UTF-8>

Notice that this will only work with Ruby 1.9, because Ruby 1.8 does not know anything about encodings. So if you are getting a NameError: uninitialized constant Encoding error, you are running a wrong version of irb.

Now we come to the Rails part. Assuming you have Rails 2.3.5 and rvm installed, we do the following:

rvm use 1.9.1 # or whatever you have to do to select the ruby 1.9 interpreter
rails sample_app
cd sample_app
script/generate scaffold article title:string description:text
script/server

Then point your browser to http://localhost:3000/articles and play around a little. Everything seems to work fine, even when saving articles with special characters. Next, try to put in special characters in the template itself. For example, try replacing “Listing articles” by “Listing cööl articles”. BAM! You’ll get a:

incompatible character encodings: UTF-8 and ASCII-8BIT

Now, this is not Rails’ fault. Our DB adapter (in this simple case sqlite3) does not properly support string encodings in Ruby 1.9. This means you will get ASCII strings from the database, no matter what you set in your database.yml. Using umlauts in the template sets the template encoding to UTF-8 automatically, so merging in ASCII strings from the database will fail. As a solution, you can install an encoding aware DB adapter. For MySQL, you’ll need to uninstall the mysql gem and install sam-mysql-ruby instead. If everything worked, you can check Article.last.title.encoding.name in irb, and get “UFT-8”. For this little example, we’ll just fake it and force the encoding of the strings returned by the database:

<td><%=h article.title.force_encoding("UTF-8") %></td>
<td><%=h article.description.force_encoding("UTF-8") %></td>

This should be working now. Next, we will use an umlaut in the label of the Rails link_to helper:

<%= link_to 'New cööl article', new_article_path %>

The next reload will show the feared mixed encoding warning, and I promise you won’t get rid of it. It’s there because the string ‘cööl’ is UTF-8 encoded, but the url that is implicitly generated by the url_for() method is ASCII encoded. You would have to hack deep into the guts of Rails to fix this. Setting the default internal encoding won’t help either, just in case you were wondering. So if you want to use umlauts or other special characters in Rails helpers, you are out of luck in many cases. As I am German, I have umlauts all over the place. Not using them is not an option for me, like for nearly everyone who lives outside of an English speaking country.

But don’t get too depressed about this, as Rails 3 is maturing and already looks very promising. So let’s just try the same as above with Rails 3 for a change. First, we check out a very bare sample application. It’s basically the same if you would have gone through the app creation, git initializing and gem bundling process yourself, so this is really very bare boned:

git clone git://github.com/ralph/sample-rails-3.0-project.git
cd rails_3_sample_app
gem bundle
script/generate scaffold article title:string description:text
script/server

If you have an encoding aware database adapter and play around here, you will see that everything works great. Again, we add a random umlaut to the index template, and everything still works. We change the helper text to include an umlaut, and everything still works. The only thing we need to take care of is installing an encoding aware database adapter, like sam-mysql-ruby, in order to be able to save special characters in the text fields. Finally, Rails 3 looks like a release I would like to use with the Ruby 1.9 interpreter.

I don’t know about you, but I can’t wait for Rails 3 to be released. I think it’s a great step forward and will help to spread the adoption of Ruby 1.9. That said, you should really try to port your apps over as soon as Rails 3 is released. I am really hoping to see an increased adoption of Ruby 1.9 instead of people sticking to 1.8. Ruby has so many advantages, and if you don’t port your stuff over, you are not helping. So be a good Rubyist, give something back to opensource. Test your stuff on 1.9 and report any errors back to the maintainers of the libs that you use. Then we can make 2010 the Ruby 1.9 year. :)

Show Comments