A look at the rails migration versioning implementation

So i took a hiatus for a while, and didnt used rails for a couple of years.

Now that i am back building a product with rails, i have noticed ActiveRecord::Migration is verioned and you need to inherit from a versioned class ActiveRecord::Migration[{n}] where n is the migration version, it could be 4.2, 5.0, 5.2 etc…

How does this works?





The naive approach:

So, the first thing i tried to do was declare a class with [5.0] at the end of the name, turns out this is not valid ruby class syntax:

test.rb:

#/usr/bin/env ruby class MyClass [ 5.0 ] def hello p "hello" end end c = MyClass . new c . hello

running the script gives us:

test.rb:1: syntax error, unexpected '

', expecting &. or :: or '[' or '.' test.rb:5: syntax error, unexpected keyword_end, expecting end-of-input

The way rails do it:

After searching on the rails source code, i stumbled at this snippet of code:

def self . [] ( version ) Compatibility . find ( version ) end

of course! now it makes sense.

the ActiveRecord[5.2] idiom is just calling the class method [] with argument 5.2 , later that method, is just doing a dynamic-dispatch with the Compatibility.find method.

Our own implementation:

Richard Feynman once said: “What I cannot create, I do not understand” so with that in mind, lets make our own implementation:

test.rb:

#/usr/bin/env ruby class MyClass def self . [] ( version ) case version when 1 V1 when 2 V2 end end end class V1 def hello p "Hello from V1" end end class V2 def hello p "Hello from V2" end end c1 = MyClass [ 1 ]. new c1 . hello c2 = MyClass [ 2 ]. new c2 . hello

running gives us the expected output:

"Hello from V1" "Hello from V2"

Conclusion:

i hope this sheds a bit of light, on the underlying “magic” rails implement, dont be afraid to dive into the source of rails and find out things on your own.

Please enable JavaScript to view the comments powered by Disqus.