Inheritance on-the-fly with Ruby on Rails
Today, I’d like to try a new format of blogpost.
Indeed, the goal here is to break down a well known piece of Ruby code that we encounter everyday.
Today we’re going to talk about the way that Ruby on Rails ensure the compatibility of your migrations when you upgrade Ruby on Rails.
All the magic is done within the
So, let’s get the party started!
We use Ruby on Rails 5.2.x.
Let’s generate a
Product model from the terminal
?> bin/rails generate model Product name:string description:text
Among all the generated files, this command will generate a migration class
CreateProducts class is generated.
At first glance, this class seems to inherit from anything but a class.
But, in Ruby, a class can only inherits from a class.
So, what happens here?
As we’ve seen in the
short guide to learning how Classes work in Ruby article, a class is an instance of the class
CreateProducts class could be defined as following — without using the
class..end syntactic sugar
Class.new method expects a class as parameter that will be set as superclass of the returned instance of
So, as expressions passed as arguments to methods are always evaluated before the method call itself, then
ActiveRecord::Migration[5.2] is evaluated and its return value — which is a class — is passed as argument of the
Class.new method call.
So what’s the
ActiveRecord::Migration[5.2] return value?
This statement is a shortcut to the
ActiveRecord::Migration.(version) class method call.
This method is in charge of returning the version of the
ActiveRecord::Migration class that corresponds to the version of Ruby on Rails passed as argument — Ruby on Rails 5.2.x in our case.
Let’s see what’s the returned class in this case
Here we see that
ActiveRecord::Migration[5.2] returns a class named as
ActiveRecord::Migration::Current and that this class inherits from
This class contains a set of changes related to the current version of Rails— 5.2 in our case.
Also, this class derivates from
ActiveRecord::Migration. So it shares all its properties.
Note that a call to
ActiveRecord::Migration[5.1] returns the
ActiveRecord::Migration::Compatibility::V5_1 class which derivates from
From 5.2 to 6.0
So, let’s suppose that we want to upgrade our app to Ruby on Rails 6.0.
To ensure the compatibility of our migrations, all our migration are version to
If so, all our migration should generate the same database schema without any effort.
Let’s see what the Ruby on Rails Team does about migration when they release a new version of Ruby on Rails:
ActiveRecord::Migration::Current is now returned by a call to
ActiveRecord::Migration[6.0] — and not
ActiveRecord::Migration::Compatibility ::V5_2 class is created and all the specialisations of the old
ActiveRecord::Migration::Current are moved within this class.
3- new changes that correspond to the Ruby on Rails 6.0 release are implemented within the
ActiveRecord::Migration[5.2] returns— in Ruby on Rails 6.0 — to
So this mechanism ensures that the same database schema is generated when a Ruby on Rails application is upgraded to a newer version of Ruby on Rails.
ActiveRecord::Migration — which is the superclass of any migration class — is versioned to avoid regression and side effects during database migration.
In effect, as the
ActiveRecord::Migration library +/- differs between each major or minor version of Ruby on Rails, then the generated schema can also slightly differ between each of these versions.
Concretely, if an app in Ruby on Rails 5.2 is upgraded to Ruby on Rails 6.0, then, when migrations are played, the generated schema can slightly differ between these versions and some undesired side effects can occur accordingly.
So, Ruby on Rails decided to version the
ActiveRecord::Migration to address this issue.
We’re currently finalizing our first online course: Ruby Mastery.
Join the list for an exclusive release alert! 🔔
Also, you can follow us on x.com as we’re very active on this platform. Indeed, we post elaborate code examples every day.