Ruby's quirky load order for mixins
posted by Ayush Newatia
17 May, 2021
Ruby modules are a great way to define mixins. This construct offers a way to share logic using composition.
As it is usually the case with Ruby, there’s two ways of mixing (or include
ing) ruby modules into your class:
class Post
include Categorizable
include Copyable
end
OR
class Post
include Categorizable, Copyable
end
At first glance you might think those two syntax are identical, but Ruby has a quirk that isn’t immediately obvious. To demonstrate this, let’s print out a line from those two module when they’re included:
module Categorizable
def self.included(base)
puts "Categorizable included"
end
end
module Copyable
def self.included(base)
puts "Copyable included"
end
end
Now we can see the what’s going on under the hood when these modules are included.
class Post
include Categorizable
include Copyable
end
Post.new # =>
# Categorizable included
# Copyable included
class Post
include Categorizable, Copyable
end
Post.new # =>
# Copyable included
# Categorizable included
As demonstrated by those above snippets, the load order of the modules in the two examples is different. The first syntax option loads from top to bottom as you’d expect. The second example however load from right to left.
In most cases this shouldn’t matter as mixins should usually be independent of each other. However it’s easy to get tripped up by this if a module depends on another module being loaded.
Here’s an example from HEY shared by DHH on how to manage this quirk without making a mess:
It’s usually best to use a combination of the two syntax as demonstrated in the image above. This makes any dependencies between the mixins blatantly obvious to anyone reading the code.
I love Ruby and it’s weird quirks like this; but it’s always good to know when something subtle like this might trip you up!