I wrote a program to help me memorize stuff a few years, partly for reviewing Japanese vocabulary (and grammar) and partly to give me an excuse to learn Rails. It’s done very well in the former regard; it was somewhat useful in the latter regard, but it’s simple enough (and used by few enough people) that it certainly hasn’t turned me into a Rails expert.

Rails is a moving target, and in particular the release of Rails 3.0 last year brought a fair amount of changes. I didn’t upgrade immediately, partly because I was busy with other things and partly because authlogic took a while to be upgraded to work with Rails 3.0. Eventually, though, authlogic got fixed, and Rails 3.1 release candidates started to appear, so I figured I should upgrade sooner rather than later or I’d be setting myself up for even more pain in the future.

As always, there was a very helpful Railscast. So with the help of it and the rails_upgrade plugin, I created a branch and started working at it.

Getting the basics working wasn’t too hard, so after a couple of hours I had something that passed all of my automated tests without any deprecation warnings. Unfortunately, when I fired it up in a browser, I found that the code to show the answer to a question didn’t work. I wasn’t completely shocked to see that, because I was aware that the move to unobtrusive JavaScript was one of the big changes in Rails 3; I knew some of the things I had to do (make sure that I included rails.js and the csrf_meta_tag), but the exact details of how to handle replacing part of a web page with code from the back end wasn’t entirely clear to me, and I didn’t find a web page that gave a completely braindead cookbook.

Having said that, it didn’t take too long to figure out an answer. And, in case it helps anybody else, here’s what I did: I started with a section of my view that looked like this:

<% form_remote_tag :url => { :action => :answer, :item => ask },
:update => "answer", :html => { :id => "show-answer" } do %>
<%= submit_tag "Answer" %>
<% end %>

and ended up with this:

<%= form_tag url_for(:action => :answer, :item => ask),
:remote => true, :id => "show-answer" do %>
<%= submit_tag "Answer" %>
<% end %>

And in the controller method I removed the render :partial line at the end, and added a view answer.js.erb containing the following:

$('answer').update("<%= escape_javascript(render :partial =>
'answer', :object => @item) %>");

Which is quite straightforward, and certainly the generated HTML is nice. The one thing that I don’t like about it is that I don’t know how to do a good job of testing what the controller method returns: when the controller method rendered HTML, I could use assert_select, but that gets harder when it renders JavaScript. (Update: I figured out a good way to test this.)

The next issue ws that the keyboard shortcut for pressing that button didn’t work. This had actually been an issue when I originally wrote that code, and the method I’d used then (calling the onclick action) no longer worked. The solution I came up with was to modify rails.js to make handleRemote public, and to call it directly, but I’m not thrilled with that, because there’s the danger that the code paths for clicking and for using the keyboard shortcut could diverge. Eventually I’ll probably switch over to using jQuery instead of Prototype, maybe $(...).click() will do the right thing there?

At that point, I pushed the code live, quickly realized that the display for newlines was broken, and reverted back. I’d already converted to using the new automatic HTML escaping mechanisms when they hit Rails 2.x; unfortunately, they changed in Rails 3.0.8 (and stayed changed in Rails 3.0.9), in a way that meant that the result of concatenating html_safe strings was no longer html_safe. I solved it by sticking an html_safe at the end of the entire block, but I don’t like that because it makes it too easy to accidentally introduce HTML-escaping bugs; maybe I’ll file a bug report on the issue.

After that, everything worked, and from start to finish it probably took around five or six hours in total (spread over a week or so), which is a quite reasonable amount of time for a major upgrade. And it feels to me like the code is faster after the upgrade, which was a pleasant bonus! Also, it got me chatting with a friend of mine who also uses memory, resulting in my improving the layout on his Android phone (to match the way it looks on iPhones); always nice to have an excuse to improve software like that. And I’m glad I got this done before Rails 3.1 appeared.

But I also wish I’d been paying a bit more attention to Rails’s evolution, so I would have been a bit more familiar with what I was in for. Honestly, I still feel a little bit conflicted about this—I don’t currently plan to become a Rails expert, and I expect I’ll give Lift a try the next time I want to write a web app—but I like Ruby and Rails enough that I don’t want to lose touch with them. (And I really do depend on this memory program, so I very much want to keep it working!) For now, I’ve subscribed to the Ruby on Rails: Talk mailing list; the signal-to-noise ratio there is, unfortunately, a lot worse than I’d like, but there’s enough signal that I’m sticking with it for the time being. And I’ll try to find time to watch a higher percentage of Railscasts than I had been doing.

Post Revisions: