In 2023, Ruby on Rails turned 20. Here's a collection of some notable changes over time.
The earliest version of Rails on GitHub is 0.9.1 and its oldest commit is from November 2004. But as creator DHH has commented, the development started a year before:
Actual development for Rails started in the summer of 2003, but back then I was on CVS, and we didn't carry that history over when we switched to SVN. Wish we did!
It's pretty interesting to see how much of the Rails structure was already in place way back then. We already had Railties, ActiveRecord, ActionPack, and ActionMailer. There were already connection adapters for SQLite, MySQL, and PostgreSQL. There were familiar classes and modules like ActionController::Base
and ActionView::Helpers
.
In 0.9.3, parts of ActionPack and ActiveRecord were split off to become ActiveSupport. Rails 1.0 was released in December 2005, followed by 2.0 two years later. Rails 2 brought ActiveModel, ActiveSupport::TimeWithZone
and more helper methods like translate
for I18n and the all-important forty_two
.
The source code was originally maintained in CVS, then SVN, and switched to Git in 2008.
I've been coding in Rails for over a decade. My first app was on Rails 3.2. Whenever I had to support a Rails 2 project, it always felt ancient. The change that marks the division in my mind between ancient and modern Rails was the introduction of the new chainable query interface which included methods like where
.
In Rails 3.0, where
replaced conditions
. This meant that instead of performing a query like:
Post.find(:all, conditions: { published: true }, include: [:author, :comments])
You could now do:
Post.where(published: true).includes(:author, :comments)
The new interface was more elegant and a real joy to work with. The modern ActiveRecord interface is one of the best things about programming in Rails.
Rails 3 also brought some other changes that made code cleaner and life easier. Gems were now managed with Bundler. The old way of mapping routes was replaced with a new RESTful routing DSL. We no longer had to use h(string)
all over view templates to escape HTML output because escaping became the default.
As Rails grew in popularity, security issues and technical limitations were bound to arise.
A particularly rough moment in Rails history was when GitHub (itself a Rails app) was hacked. In an infamous commit in March 2012, a hacker made an update to the master
branch of Rails. As a result, in Rails 4.0, the strong_parameters
gem was pulled into Rails core. Scaffold generators were updated to provide a secure starting point and to help developers avoid the insecure mass assignment pattern.
If you're fortunate enough to have an app that just keeps on growing, you'll soon find out that 2 billion is not a very large number and that the original Rails default primary key data type of int
was not a great choice. Rails made it all the way until version 5.1 (over 13 years) before the primary key default was changed to bigint
. It can take a long time to migrate existing data. Basecamp went into read-only mode for an entire morning in November 2018 when they unexpectedly ran out of IDs.
In versions 4, 5, and 6 Rails continued to beef up with many sizable new features.
Turbolinks provided faster page loads. secrets.yml
improved credential distribution. ActiveRecord::Enum
made it easy to define enum values.
ActionCable integrated with WebSockets. ActiveStorage provided file management. ActionText delivered rich text editing.
There were a lot of smaller wins, too. Foreign key management that used to require the foreigner
gem was brought into Rails. The rails/info/routes
helper path replaced the need for the sextant
gem.
When Rails 7.0 was released in December 2021, the "Major Features" section of the release notes was empty. It was a time for pruning the framework of deprecated code. Webpacker was out. It had been the default JavaScript compiler for Rails 6 but was being replaced by import maps or other bundlers. Sprockets was removed.
On the horizon are changes related to deploy management. Default Dockerfiles were added in 7.1. Kamal will be the default deploy solution in Rails 8.
As time moves on, Rails continues to adapt and evolve. Features have been moving in and out of the app for as long as it has existed. Rails 1 had ActionWebService and an excess of SQL adapters which were all removed or extracted to gems before Rails 2. Rails 2 had ActiveResource which was moved out to a gem before Rails 4.
The Rails core team members have been good stewards, reshaping the framework over time. I'm looking forward to what the next 20 years will bring.