The Inherited Hook Method in Ruby - and More Parenting Lessons
Tags: ruby, learning, beginners
Published: 2019-09-03 13:53:39

---
title: "The Inherited Hook Method in Ruby - and More Parenting Lessons"
description: "Today, we will explore the inherited hook method and dive into preventing inheritance"
published: true
cover_image: https://blog.appsignal.com/images/blog/2019-10/inherited-hook.jpg
canonical_url: https://blog.appsignal.com/2019/09/03/inherited-hook-method-and-parenting.html
tags: #ruby, #learning, #beginners
---

Hello children and parents, ahem Rubyists. In an earlier article, we dove into [the ancestry chain](https://blog.appsignal.com/2019/05/07/method-missing.html). In today's post, we'll dive deeper into parenting and inheritance. We will explore the inherited hook method and look into preventing inheritance.

## When Kids Inherit 101: The Inherited Hook Method
Let's start with a look at how parenthood is declared. Ruby provides a neat way of interacting with a class when it is declared as the parent of another class.

```ruby
class Parent
  def self.inherited(subclass)
    puts "#{subclass} inherits from Parent"
  end
end

class Child < Parent
end
```

Running this code prints out "Child inherits from Parent", as the `Parent.inherited` method is called when the `Child` class inherits from `Parent`. Note that this method takes the subclass as parameter—`Child`, in our case. This mechanism allows you to interact with the Parent class to define a set of behaviors only if it is inherited. By behavior, in this context, we mean modifying, defining or deleting variables, methods and constants on the inheriting or the inherited class.

Now, let's define the `parent_name` method on-the-fly:

```ruby
class Parent
  def self.inherited(subclass)
    subclass.define_method :parent_name do
      "Daddy"
    end
  end
end

class Child < Parent
end

Child.new.parent_name # => "Daddy"
```

Here, we define a method on the `Child` class when it inherits from the `Parent` class, but without adding that method directly to the `Parent` class. Instead, it's only defined when another class inherits from `Parent`.

Alright, we've covered the theory, now let’s take a look at a more realistic example in the life of a Rubyist.

## Prevent Class Inheritance
In Ruby on Rails, database migrations are handled by the `ActiveRecord::Migration` class. Let’s try to directly inherit from this class.

```ruby
class AddFirstnameToUsers < ActiveRecord::Migration
end

# => StandardError (Directly inheriting from ActiveRecord::Migration is not supported..)
```

This error is raised because Ruby on Rails provides a mechanism that prevents us from inheriting from this class. So why did Ruby on Rails implement this mechanism?

A migration is strongly coupled to a specific version of Ruby on Rails. Indeed, the API provided by this class can slightly change between 2 versions. So, to avoid breaking migrations when you upgrade Ruby on Rails, the framework forces you to choose a specific version of the ActiveRecord::Migration class. This ensures the smooth running of your migrations.

```ruby
class AddFirstnameToUsers < ActiveRecord::Migration[4.2]
end
```

In the example above, our migration is coupled to the `ActiveRecord::Migration` API provided with version 4.2 of Ruby on Rails. So, even if we upgrade our application to version 5.0, our migrations will still run smoothly because they'll still run with version 4.2 of the `ActiveRecord::Migration` API.

## How Preventing Inheritance Works
Now that we understand **why** inheritance is prevented here, let’s see **how** this `ActiveRecord::Migration` prevents inheritance. All the logic is defined in the `ActiveRecord::Migration.inherited` method.

```ruby
class AddFirstnameToUsers < ActiveRecord::Migration[4.2]
end
```

When our `AddFirstnameToUsers` class inherits from `ActiveRecord::Migration`, the `ActiveRecord::Migration.inherited` hook method is called.

```ruby
module ActiveRecord
  class Migration
    def self.inherited(subclass) #:nodoc:
      super
      if subclass.superclass == Migration
        raise StandardError, "Directly inheriting from ActiveRecord::Migration is not supported. " \
          "Please specify the Rails release the migration was written for:\n" \
          "\n" \
          "  class #{subclass} < ActiveRecord::Migration[4.2]"
      end
    end
  end
end
```

As we can see, this hook method checks if the subclass (`AddFirstnameToUsers`) directly inherits from `ActiveRecord::Migration`. If it does, an error is raised. This is the perfect entry point for controlling inheritance.

## Conclusion
Today, we covered the basics of inheritance and preventing inheritance. We covered the inherited hook method and saw how it can be very handy when interacting with the inheriting/inherited class on-the-fly.

In a real-world setting, watch out when playing with inheritance. Be very cautious when you remove or override an existing method or class. This could result in some unwanted side effects. Children may stop calling you daddy.

Et Voilà, this concludes our post for today!