Steve Klabnik wrote a great article called Rails has Two Default Stacks. This is the best mental model I’ve found for the major factions within the rails community.

It breaks down if you start considering various deployment options, but I realized that it’s better not to. Deployment stacks can change more rapidly, and have more reasons for needing to change, than development stacks. It is worth just thinking about the development stack, of which testing is a major part. It is the development stack that plays the biggest role in programmer happiness.

If you work on a large project, thinking about just the development side of things will probably make your (Dev)Ops people happy, too.

Today I upgraded to rails 2.3.5 on a server that had an old version of Ubuntu. This is with an old version of ruby 1.9 that was installed using the Ubuntu packages rather than rvm. Here’s what I had to do:

1. Change the rails version

I changed the version in config/environment.rb to 2.3.15.

RAILS_GEM_VERSION = '2.3.15' unless defined? RAILS_GEM_VERSION

More information here.

2. Turn off yaml and symbol deserialization

Add this to config/environment.rb, just before the last end statement (at the end of the configuration block):

  ActiveSupport::CoreExtensions::Hash::Conversions::XML_PARSING.delete('symbol')
  ActiveSupport::CoreExtensions::Hash::Conversions::XML_PARSING.delete('yaml')

More information here. This is apparently also solved by the rails update above, but since this flaw is so harmful I’m glad to have it fixed in more than one place.

3. Require thread

I got this from a StackOverflow post. I added this to the top of config/boot.rb:

require 'thread'

# Don't change this file!
# Configure your app in config/environment.rb and config/environments/*.rb

It says not to change the file, but in this case I am not changing the file to customize my rails app but to make it work with a newer version. I’m not sure this step was necessary.

3. Upgrade rubygems

I had an old version of rubygems. It was installed with apt-get, so I couldn’t upgrade it with gem update --system. Furthermore, since I was running an old version of Ubuntu, apt-get upgrades weren’t working for me. So instead I uninstalled rubygems and installed it from source.

5. Install the gems

I installed the gems for rails with gem install rails --version 2.3.15 and also installed thin and mysql.

6. Restart the web server

Finally I restarted the web server.

Now, this is just one system configuration and chances are most are different so this may not help you. The uninstalling of rubygems and reinstallation from source took quite a while to figure out so I thought I’d share. If this doesn’t solve your problem, you may leave a comment and if I have time I’ll try to help you figure out what went wrong with yours.

There are a lot of rails 2.3.x apps that have slipped out of maintenance but are still used. When it comes time to add a feature to them, the original developer may be unavailable or may not have the same configuration for running it in development mode. I found myself in that situation and here’s what I did to run it:

  1. Start a new vagrant instance with Ubuntu. This makes things easy to install.
  2. Install rvm and the same ruby version. The project I received had a .rvmrc which specified a version of 1.8.7. The first time I told rvm to install the old version of ruby, I exited after rvm game me a list of packages to install, and installed those packages. Then I told rvm to install ruby again and it worked.
  3. Install the version of rails. It’s in config/environment.rb. Mine was 2.3.5. I ran “gem install rails -v 2.3.5”.
  4. Install dependencies specified in config/environment.rb. On this project it was just prawn, the pdf generator.
  5. Set up the database. This was the usual drill on this project. Nothing different from a new version of rails, except it was mysql instead of mysql2. I installed the Ubuntu database packages (libmysqlclient-devel and mysql-server), set up the database according to config/database.yml, and tried running rake db:migrate and after that failed ran rake db:schema:load.
  6. Go back to an old version of rubygems. I ran “gem update –system 1.5.3”
  7. Go back to an old version of rake. The breaking changes in rake were pretty much the worst thing ever. Switch to the global gemset and uninstall rake, and install rake again with “gem install rake –version=0.8.7”. If you’re having trouble with rake, 0.8.7 is probably the version you’ll want.

After that you’ll hopefully be able to run commands in script/ as well as rake commands.

In my experience it’s enough of a pain to go from 2.3.5 to 2.3.14 that it might be better to just go from 2.3.5 to the latest 3.x version. This will require a lot of changes but it will make the app ready to be worked on by most rails developers again.

I’m working on a project where I think I’ll be using a parser library so I’ve been looking at the options. One thing I’ve noticed is that treetop is installed when Rails is installed. I didn’t know why, though, so I looked around.

First I looked at the Gemfile.lock. Had I known the format I would have found out my answer more quickly. I didn’t, though, and so when I found my first result for treetop, I stopped. It showed treetop below specs in the hierarchy.

GEM
  remote: http://rubygems.org/
  specs:
    # ...snip...
    thor (0.14.6)
    tilt (1.3.3)
    treetop (1.4.10)
      polyglot
      polyglot (>= 0.3.1)
    tzinfo (0.3.30)
    uglifier (1.0.3)

The next thing I did was run find . -iname '*.treetop' in ~/.rbenv. It found the following results:

(mbp) ~/.rbenv/versions/1.9.2-p290 $ find . -iname '*.treetop'
./lib/ruby/gems/1.9.1/gems/erector-0.8.3/lib/erector/erect/rhtml.treetop
./lib/ruby/gems/1.9.1/gems/mail-2.3.0/lib/mail/parsers/address_lists.treetop
./lib/ruby/gems/1.9.1/gems/mail-2.3.0/lib/mail/parsers/content_disposition.treetop
./lib/ruby/gems/1.9.1/gems/mail-2.3.0/lib/mail/parsers/content_location.treetop
./lib/ruby/gems/1.9.1/gems/mail-2.3.0/lib/mail/parsers/content_transfer_encoding.treetop
./lib/ruby/gems/1.9.1/gems/mail-2.3.0/lib/mail/parsers/content_type.treetop
./lib/ruby/gems/1.9.1/gems/mail-2.3.0/lib/mail/parsers/date_time.treetop
./lib/ruby/gems/1.9.1/gems/mail-2.3.0/lib/mail/parsers/envelope_from.treetop
./lib/ruby/gems/1.9.1/gems/mail-2.3.0/lib/mail/parsers/message_ids.treetop
./lib/ruby/gems/1.9.1/gems/mail-2.3.0/lib/mail/parsers/mime_version.treetop
./lib/ruby/gems/1.9.1/gems/mail-2.3.0/lib/mail/parsers/phrase_lists.treetop
./lib/ruby/gems/1.9.1/gems/mail-2.3.0/lib/mail/parsers/received.treetop
./lib/ruby/gems/1.9.1/gems/mail-2.3.0/lib/mail/parsers/rfc2045.treetop
./lib/ruby/gems/1.9.1/gems/mail-2.3.0/lib/mail/parsers/rfc2822.treetop
./lib/ruby/gems/1.9.1/gems/mail-2.3.0/lib/mail/parsers/rfc2822_obsolete.treetop
./lib/ruby/gems/1.9.1/gems/treetop-1.4.10/examples/lambda_calculus/arithmetic.treetop
./lib/ruby/gems/1.9.1/gems/treetop-1.4.10/examples/lambda_calculus/lambda_calculus.treetop
./lib/ruby/gems/1.9.1/gems/treetop-1.4.10/lib/treetop/compiler/metagrammar.treetop
./lib/ruby/gems/1.9.1/gems/treetop-1.4.10/spec/compiler/test_grammar.treetop
./lib/ruby/gems/1.9.1/gems/treetop-1.4.10/spec/compiler/test_grammar_do.treetop
./lib/ruby/gems/1.9.1/gems/treetop-1.4.10/spec/composition/a.treetop
./lib/ruby/gems/1.9.1/gems/treetop-1.4.10/spec/composition/b.treetop
./lib/ruby/gems/1.9.1/gems/treetop-1.4.10/spec/composition/c.treetop
./lib/ruby/gems/1.9.1/gems/treetop-1.4.10/spec/composition/d.treetop
./lib/ruby/gems/1.9.1/gems/treetop-1.4.10/spec/composition/f.treetop
./lib/ruby/gems/1.9.1/gems/treetop-1.4.10/spec/composition/subfolder/e_includes_c.treetop
(mbp) ~/.rbenv/versions/1.9.2-p290 $

Aha, so there are numerous treetop files in actionmailer! I have my answer. Seems like a good use of a parser, plus those may be worth using as examples.

Then I took another look at a Gemfile.lock from a rails project, and saw that it was plainly listed there. I just didn’t see it and didn’t keep looking after I found one.

GEM
  remote: http://rubygems.org/
  specs:
    XMLCanonicalizer (1.0.1)
      log4r (>= 1.0.4)
    actionmailer (3.1.1)
      actionpack (= 3.1.1)
      mail (~> 2.3.0)
  # ...snip...

I noticed something: Gemfile.lock doesn’t show an arbitrarily nested hierarchy; instead it shows a list of gems and their dependencies, where the list of gems includes all gems. Then, separately at the end of the file, it shows the top-level gems from the Gemfile.

To see a deeply nested, a graph could be constructed from the Gemfile.lock, using the two nesting levels under specs as an adjacency list.

Rails 3.1 has a serialize function that can take a custom column coder. A custom coder needs to have dump and load methods set, or else it will be recognized as a required type for the built-in YAML coder called YAMLColumn.

While the JSON class has the two required methods, it doesn’t allow specifying a default. So I created a custom coder. I don’t know where the best file and module locations to put the class in are, so I won’t include them here. This is the class, though:

class JSONColumn
  def initialize(default={})
    @default = default
  end

  # this might be the database default and we should plan for empty strings or nils
  def load(s)
    s.present? ? JSON.load(s) : @default.clone
  end

  # this should only be nil or an object that serializes to JSON (like a hash or array)
  def dump(o)
    JSON.dump(o || @default)
  end
end

Since load and dump are instance methods, an instance of JSONColumn needs to be passed rather than the class. Here’s an example that works for me inside of the rails console:

class Person < ActiveRecord::Base
  validate :name, :pets, :presence => true
  serialize :pets, JSONColumn.new([])
end

Update: Added .clone to the load method. HT @miyagawa.

Here is a list of a few awesome sites offering tools for learning Rails:

PeepCode

Pricing: Starts at $12 for one screencast; Twitter: @peepcode and @topfunky

I bought my first PeepCode screencast back in 2008, before Rails and Merb merged. It’s been around for a while, but Geoffrey Grosenbach does a great job of keeping it up-to-date. There are now a number of screencasts about current topics of interest to the Ruby on Rails community, including Rails 3, Backbone.js, PostgreSQL, CoffeeScript, and John Barnette.

Railscasts

Pricing: Free weekly episodes, additional weekly episodes and revised episodes for $9/mo (RailsCasts Pro); Twitter: @railscasts

Railscasts is great for keeping up on Ruby On Rails, and because it’s free, it’s also great for recommending to people who are curious about Rails but not ready to spend money to help them learn it. Ryan Bates is great at explaining things. He covers a wide variety of topics in his screencasts and presents them in a nice format with code snippets.

Update: since I posted this Ryan Bates released Railscasts Pro, which is fantastic!

Ruby on Rails Tutorial

Pricing: $26 (book), $85 (screencasts), $95 (both); Twitter: @railstutorial

Michael Hartl is a physicist who does a number of other things (see his about page) including Web Development with Ruby On Rails. I’ve watched all of his screencasts; they’re fantastic. He builds a web application TDD-style and teaches many different concepts including MVC and how TDD can help with authorization (which is trickier than authentication IMO).

Rails Apps

Pricing: Free; Twitter: @rails_apps

I always thought that the Rails Starter App templates were cool, but they were missing something: in-depth tutorials and a comparison between the many different templates and quick-start tools. Daniel Kehoe has provided both and many more useful resources in his Rails Apps GitHub account.

Code School

Pricing: Free (one substantial free product), $45-55 (single paid products); Twitter: @codeschool

Code School is a set of tutorials designed to help developers to quickly get up to speed building web applications. Gregg Pollack and Envy Labs have been doing podcasts and screencasts for quite some time, and it’s not surprising that they still do it, because they’re very enthusiastic in front of a camera and a microphone.

Over the last week I’ve been learning how to quickly develop simple applications in Rails without looking at API documentation. Each day I’ve been starting from scratch and seeing what I can create in an hour, only consulting documentation when I really need help. The first day I didn’t use scaffolds and I only got creating, reading, and deleting working with a single model. From the second day until today I’ve been using scaffolds. On Friday I got two models with a has_many association and image attachments (using paperclip) working. Each day I start from scratch, not copying or referencing the code from the previous day (though I do save the code). I think starting from scratch each time has helped me learn more quickly than I would if I were to use the last code each time.

Today I went back to working without scaffolds. Since I’ve been trying to read the documentation as little as possible while developing, I had to figure some things out for myself. One thing I had to think of was the list of actions to type when generating a controller. Here is what I came up with:

script/generate controller Planets index new show edit create update destroy

I’m obsessive-compulsive, so not only did I try to remember what actions are used in scaffolds, I tried to put them in an order that makes sense to me. I put index first because index is special. After that, there were two sensible approaches I could think of to order the remaining actions. I could either order by CRUD or order by whether or not the actions have views. Either way, I would use the other ordering technique within groups. I went with ordering first by whether or not actions have views, and then by CRUD. I started with the actions that have views because it’s nice to have them at the top when jumping from a view to its controller.

Here’s my thought process in a tabular format:

Create Read Update Delete
Has View new show edit *
No View create ** update destroy

Notice that there are a couple of holes in the table. The first one (*) is missing because the interface for deleting is built into the index. It doesn’t have to be this way, and in fact varies widely on the web. It could have its own page, or it could be on the show or even edit page (Side note: I think it’s bad UI to put the delete button on the edit page because the edit form doesn’t fit into the workflow of deleting an item. The user may want to look at an item before deleting it to make sure it’s something they don’t need, but they’re unlikely to want to edit an item). The second one (**) is missing because in the simple case reading is achieved entirely through GET requests.

One thing that’s convenient about having the ones without views at the end is that it makes it easy for me to remember which skeleton views to delete after running the generate command. It’s the last three.

It used to take me a minute or a few to remember what actions I need, but now that I have this mnemonic it should only take a few seconds.

Now, I place a certain level of importance on conventions. After I came up with this mnemonic I looked at a scaffold to see how rails orders things. The only difference between my ICRUDCRUD ordering (index, CRUD with views, CRUD without) or ICRUCUD ordering and the standard scaffold ordering is that the show and new actions are swapped. So rails uses the RCUD ordering. Fair enough. I have pontificated on whether the ordering in CRUD makes sense or is a bacronym. Create and read are pretty useless without eachother. Below is the table with the RCUD ordering. I threw index into the empty cell. If you read the first line left to right, then move down, like a book, the order is the same as it is in a scaffold:

The order of actions in a scaffold
index Read Create Update Delete
Has View show new edit *
No View ** create update destroy

Now, how to remember RCUD? Well, remembering to swap C and R is one way, but I prefer to think of a Rails cow chewing its CUD.

rcud

Original image from cerulean5000 on flickr. Used by Creative Commons license.

I’m at the Merb and Rails 3 community forum with Yehuda Katz and Matt Amionetti right now. It’s an event with no agenda; they just opened the floor to questions. I asked them a couple of questions about Merb slices.

First, I asked them what would happen with slices in Rails 3. They explained that slices are going away in future versions of Rails and Merb, but the functionality will still be there. Instead of having slices, applications will simply be “mountable” within other applications.

I then asked if components such as models could be shared between slices. Yehuda said that their goal was to give all applications a namespace by default. He then went on to say that hopefully there will be no need to refer to an application’s namespace from within the application.

This sounds great! With a few contributions from the community, it should be at least as easy to install multiple apps into a site and get them sharing stuff as it currently is in Django.