How OOP Inheritance Works in Ruby
In this lesson, we are going to learn about an important object-oriented principle called inheritance. Before going into how it is executed in Ruby, let's see why it's important for building applications.
Guide Tasks
  • Read Tutorial
  • Watch Guide Video
Video locked
This video is viewable to users with a Bottega Bootcamp license

In this lesson, we are going to learn about an important object-oriented principle called inheritance. Before going into how it is executed in Ruby, let's see why it's important for building applications.

To start with, inheritance means your classes can have a hierarchy. It is best used when different classes have some shared responsibilities, since it would be a poor practice to duplicate code in each class for identical or even similar behavior.

For example, we have been working on our ApiConnector class over the last few lessons. Let's say we have different API classes for various platforms, but each class shares a number of common data or processes. Instead of duplicating code in each of the API connector classes, we can have one parent class with the shared data and methods. From there we can create child classes from this parent class. With the way that inheritance works, each of the child classes will have access to the components provided from the parent class.

For example, we have four APIs, namely, SmsConnector, PhoneConnector, MailerConnector and XyzConnector. If we wrote code individually for each of these classes, it would like this:

class SmsConnector
  def initialize(title:, description:, url: 'google.com')
    @title = title
    @description = description
    @url = url
  end

  def send_sms
    puts "Sending SMS message..."
  end
end

class MailerConnector
  def initialize(title:, description:, url: 'google.com')
    @title = title
    @description = description
    @url = url
  end

  def send_mail
    puts "Sending mail message..."
  end
end

class PhoneConnector
  def initialize(title:, description:, url: 'google.com')
    @title = title
    @description = description
    @url = url
  end

  def place_call
    puts "Placing phone call..."
  end
end

class XyzConnector
  def initialize(title:, description:, url: 'google.com')
    @title = title
    @description = description
    @url = url
  end

  def does_something_else
    puts "Secret stuff..."
  end
end

If you see, we are simply repeating the same code across different classes. This is considered a poor programming practice.

Instead, we can make an ApiConnector parent class, and the each of the other classes can inherit the common functionality from this class.

class ApiConnector
  def initialize(title:, description:, url: 'google.com')
    @title = title
    @description = description
    @url = url
  end
end

class SmsConnector < ApiConnector
  def send_sms
    puts "Sending SMS message..."
  end
end

class MailerConnector < ApiConnector
  def send_mail
    puts "Sending mail message..."
  end
end

class PhoneConnector < ApiConnector
  def place_call
    puts "Placing phone call..."
  end
end

class XyzConnector < ApiConnector
  def does_something_else
    puts "Secret stuff..."
  end
end

By leveraging inheritance we were able to cut all of the duplicate code throughout our classes.

The syntax for using inheritance is to define the class name followed by the symbol <, followed by the parent class name. For example our SmsConnector class inherits from the ApiConnector with the following syntax:

class SmsConnector < ApiConnector

Each of these child classes now have access to the full set of elements provided in the parent ApiConnector class. We can test this out by adding the attributes to the send_sms method inside of the SmsConnector class, like this:

class SmsConnector < ApiConnector
  def send_sms
    puts "Sending SMS message with the #{@title} and #{@description}"
  end
end

Now if we create a new instance of SmsConnector with the following parameters we can call the send_sms method:

sms = SmsConnector.new(title: "Hi there!", description: "I'm in a SMS message")
sms.send_sms

Running this code will give the following output:

Sending SMS message with the Hi there! and I'm in a SMS message

A rule of thumb in OOP is to ensure that a class performs a single responsibility. For example, the ApiConnector class should not send sms messages, make phone calls or send emails since that would three core responsibilities. Our file is taking a better strategy by creating child class for each of these functionalities.

For practice you can create new instances of each class and then call each of the methods present inside the respective classes.

The code to instantiate each of the classes and call the methods is here:

sms = SmsConnector.new(title: "Hi there!", description: "I'm in a SMS message")
mail = MailerConnector.new(title: "Hi there!", description: "I'm in an email message")
phone = PhoneConnector.new(title: "Hi there!", description: "I'm on a call")
xyz = XyzConnector.new(title: "Hi there!", description: "Who knows what I'm in")

sms.send_sms
mail.send_mail
phone.place_call
xyz.does_something_else

So, that's how inheritance works in Ruby. The key to remember about inheritance is that it gives you the ability to clean up your codebase and created inherited classes that share common behavior.