More Ruby Fundamentals: Inheritance, Mixins, & Modules

Free Ruby on Rails Tutorial

Dive deep into the world of Ruby on Rails and learn about inheritance, overriding a parent class’s method, calling a parent class’s method using super, and understanding mixins and modules with this comprehensive tutorial.

This exercise is excerpted from Noble Desktop’s past web development training materials. Noble Desktop now teaches JavaScript and the MERN Stack in our Full Stack Development Certificate. To learn current skills in web development, check out our coding bootcamps in NYC and live online.

Topics covered in this Ruby on Rails tutorial:

Inheritance, Overriding a parent class’s method, Calling a parent class’s method using super, Mixins & modules

Exercise Overview

Time for a Ruby break!

Now that we’ve got our feet wet building a real Rails site, let’s pause to take in some of the more advanced (but no less important) features of the Ruby language before pressing on.

Full-Stack Web Development Certificate: Live & Hands-on, In NYC or Online, 0% Financing, 1-on-1 Mentoring, Free Retake, Job Prep. Named a Top Bootcamp by Forbes, Fortune, & Time Out. Noble Desktop. Learn More.

In this exercise, you’ll learn about how information is shared by exploring inheritance, mixins, and modules.

Inheritance

Inheritance, as the name suggests, allows objects to inherit properties and methods from one another.

  1. If Interactive Ruby isn’t running, go to/open Terminal and type the irb command.

  2. To see how inheritance works, create a Pet class by typing the following:

    class Pet
       attr_accessor :name
       def initialize(name)
          @name = name
          end
    
  3. Type the following to define the speak method for the Pet class:

       def speak
          "Feed me!"
          end
       end
    
  4. Create a new instance of the Pet class by typing:

    fluffy = Pet.new("Miss Fluffy")
    
  5. Check fluffy’s name:

    fluffy.name
    
  6. Ask fluffy to speak:

    fluffy.speak
    

    Terminal should return what all pets always say: "Feed me!"

  7. Let’s create a class that inherits from the Pet class. We indicate inheritance with the less than symbol ( < ). It is helpful to think of it as an arrow pointing from the parent class towards the child class. We want the Dog class to inherit from the Pet class, so type the following:

    class Dog < Pet
       end
    

    The Pet class can now be referred to as a superclass (or parent class) because it has a child class, Dog.

  8. As a child class of the Pet superclass, the new Dog class should automatically say "Feed me!" when asked to speak. To make sure, type the following:

    fido = Dog.new("Mr. Fido")
    fido.speak
    

    Terminal should return: "Feed me!"

  9. We can override existing methods within this class by redefining the method in the class definition. Type:

    class Dog < Pet
       def speak
          "Arf! Arf!"
          end
       end
    
    fido.speak
    

    Terminal should now print "Arf! Arf!" instead of "Feed me!" (the default for the Pet superclass) because we redefined the speak method within the Dog class, and this supersedes the default speak method of the parent class.

  10. Type the following:

    fido.name
    

    Terminal should print "Mr. Fido". Fido knows his name because the Dog class inherited the attr_accessor :name method from its parent class (Pet).

  11. Create a new child class of the Pet superclass by typing the following:

    class Reptile < Pet
       end
    
  12. Create a new instance of the Reptile class:

    sandra = Reptile.new("Mrs. Sandra")
    sandra.name
    sandra.speak
    

    From the last two lines returned by Terminal, we can see that Sandra knows her name and says "Feed me!" by default, all because of inheritance from the Pet class!

  13. In the Dog class, we overwrote the speak method, but what if we wanted to add on to the existing method? We would use the super method. Let’s try it now. Create a new child class of Pet and call super as shown:

    class Fish < Pet
       def speak
          super + " (bubble bubble)"
          end
       end
    
  14. Create a new instance of the Fish class:

    sunny = Fish.new("Mr. Sunny")
    sunny.speak
    

    Terminal should return "Feed me! (bubble bubble)" because we used the super command, which gets "Feed me!" from the speak method in the Pet class, and then appends the additional " (bubble bubble)" string that is specific to the Fish class.

Mixins

Inheritance is the primary way that most object-oriented languages share methods between classes, but Ruby offers an additional strategy called mixins. Mixins are much more flexible than simple inheritance, and they allow you to share methods between classes without requiring those classes to have the same parent class. Mixins live in code structures called modules. (Modules aren’t exactly classes in themselves, but ways of keeping pieces of code separate from one another.)

  1. Create a module for another possible property of a Pet (a license) by typing:

    module License
       def register(state)
          @name + " has been registered in " + state
          end
       end
    

    We’ve just created a License module, but we can’t really do anything with it until we mix it into a class.

  2. Use the License module to extend the Pet superclass by typing the following:

    class Pet
       include License
       end
    

    NOTE: We extended the Pet class to include the License module with the include statement. This powerful statement actually extends the Pet class to include any and all of the License module’s methods and properties.

  3. Let’s think of something else that has a license but would not necessarily inherit from the Pet superclass. Create a Car class by typing:

    class Car
       include License
       def initialize(model, owner)
          @name = owner + "'s " + model
          end
       end
    

    NOTE: Just to be fancy, when we defined initialize(model, owner), we passed it two parameters in parentheses instead of just one!

  4. We are done defining our classes, and now we can try them out. Register Fido by typing the following:

    fido.register("Oklahoma")
    

    Terminal should return "Mr. Fido has been registered in Oklahoma". Excellent! This all worked correctly because of inheritance: Fido belongs to the Dog class, a child of the Pet class. Because of inheritance from the Pet class, he knows his name, and because we extended Pet to include the License mixin, the license structure will automatically apply to the Dog class!

  5. Create and register a car by typing the following:

    car = Car.new("BMW", "Grandpa")
    car.register("Wyoming")
    

    Success, Terminal should return "Grandpa's BMW has been registered in Wyoming"! Thanks to the beauty of mixins, we didn’t have to repeat ourselves by writing separate registration methods for the separate classes of pets and cars.

    NOTE: Remember one of the most important tenets of programming is DRY: Don’t Repeat Yourself. Mixins and modules are key to staying DRY!

The is_a? & respond_to? Methods

  1. We can also find out whether a given object is a member of a particular class using the is_a? method. This works just as well for parent classes as for an object’s immediate class. Type:

    fido.is_a? Dog
    fido.is_a? Pet
    

    Terminal will affirm both are true.

  2. Let’s check if fluffy is a Dog:

    fluffy.is_a? Dog
    

    Indeed, this is true.

  3. On the other hand, let’s check if fluffy is a Dog:

    sandra.is_a? Dog
    

    Well, apparently not! As you can see, this is a quick way to check whether or not an object belongs to a particular class.

    Another useful method is the respond_to? method. This lets you find out whether an object will respond to a given method.

  4. To see how this works, start by creating a Cat class with a new method:

    class Cat < Pet
       def meow
          puts "Meow!"
          end
       end
    
  5. Let’s see if fluffy responds to the meow method. There are two ways we can write it (passing either a symbol or a string). In Ruby, it’s more common to pass it as a symbol. Go ahead and try both:

    • fluffy = Cat.new('Miss Fluffy')
    • fluffy.respond_to? :meow
    • fluffy.respond_to? 'meow'

    Terminal should return true for each line.

  6. If we ask if fido will respond to meow…

    fido.respond_to? :meow
    

    The answer, of course, is false.

Noble Desktop Publishing Team

The Noble Desktop Publishing Team includes writers, editors, instructors, and industry experts who collaborate to publish up-to-date content on today's top skills and software. From career guides to software tutorials to introductory video courses, Noble aims to produce relevant learning resources for people interested in coding, design, data, marketing, and other in-demand professions.

More articles by Noble Desktop Publishing Team

How to Learn Coding

Master coding with hands-on training. Learning how to code in JavaScript, Python, and other popular languages can pave the way to a job in tech, such as web development, data science & analytics, or software engineering.

Yelp Facebook LinkedIn YouTube Twitter Instagram