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 ActiveRecord::Migration
class.
So, let’s get the party started!
Case Study
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
Here a 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?
Class.new(super)
As we’ve seen in the short guide to learning how Classes work in Ruby
article, a class is an instance of the class Class
.
So, our CreateProducts
class could be defined as following — without using the class..end
syntactic sugar
Normally, the Class.new
method expects a class as parameter that will be set as superclass of the returned instance of Class
.
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 theActiveRecord::Migration[5.2]
return value?
ActiveRecord::Migration.[](version)
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 ActiveRecord::Migration
.
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 ActiveRecord::Migration::Current
.
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 ActiveRecord::Migration[5.2]
.
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:
1- The ActiveRecord::Migration::Current
is now returned by a call to ActiveRecord::Migration[6.0]
— and not [5.2]
anymore.
2- An 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::Current
class.
4-ActiveRecord::Migration[5.2]
returns— in Ruby on Rails 6.0 — to ActiveRecord::Migration::Compatibility::V5_2
.
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.
Conclusion
The 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.
Ruby Mastery
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.
💚