Lesson Weekend

So far we've focused on using local and instance variables. In this lesson, we'll explore using class variables. We'll discuss what they are, how to use them, and why we should generally avoid them. Then we'll use class variables to build out the class methods we discussed in the last lesson. Don't worry… we'll also make it clear why we're using class variables now even though we'll want to avoid them in the future! Once again, we are not adding any code to our application yet. You are welcome to try out the Ruby code in IRB instead, though you won't be able to try out the test in IRB. Don't worry — we'll be going through this exact example and test again in a few lessons.

A class variable is scoped to a class. It's available anywhere in the class, including in all instances of the class. Let's look at our Album example again. We can temporarily store all the albums in a class variable:

class Album
  @@albums = {}
end

Now we can write our all() method. A basic test for the method looks like this (you won't be able to add this test to IRB):

describe(".all") do
  it("is empty at first") do
    expect(Album.all()).to(eq([]))
  end
end

By the way, the fact that we are expecting Album.all() to return an empty array when @@albums is currently an empty hash may look like a typo but it's not. You'll see why in a moment.

And this would be the code to make it pass:

class Album
  @@albums = {}

  def self.all()
    @@albums.values
  end
end

Our all() method takes advantage of Ruby's implicit return to return the list of @@albums.values. This method returns all the values of a hash in the form of an array. That's why even though `@@albums is a hash, Album.all returns an array.

To try this in IRB, copy over all the code above (except for the test), and then add the following:

Album.all()

You'll see it returns the [] where we will store our albums. And as you can see, @@albums is available everywhere in the Album class and isn't scoped to any specific method. However, just to clarify, it is still scoped to the class itself — we can't just type in @@albums in IRB outside of the Album class.

We'll write some additional methods to actually add albums to @@albums soon, but first let's take a closer look at class variables, why they can be useful, and why they should almost always be avoided.

The Problem with Class Variables


Class variables allow us to store information inside of a class. While this can come in handy, there are serious problems with using them. Class variables aren't just available to the class where they live; they're also available to all subclasses (child classes) as well. In other words, subclasses inherit class variables from their ancestors. Let's take a look at an example. Optionally, try this example out in IRB.

class Album
  @@albums = "Here's a list of albums!"
end

class InheritsFromAlbum < Album
  def self.all()
    @@albums
  end
end

InheritsFromAlbum.all()
=> "Here's a list of albums!"

Because class variables are inherited, they aren't much better than global variables. They "pollute" subclasses, which can quickly become a big mess in larger applications. In other words, class variables aren't very well encapsulated and should generally be avoided.

Class variables are still a core part of the Ruby language, so it's important to understand how they work. We'll use class variables in this course section in order to mock a database. They'll allow us to temporarily store information (such as all the albums in a list). Starting in the next course section, we'll use databases to store our information and we'll leave class variables behind.

Incorporating class variables into an application will also enable us to learning how to use class methods without worrying about databases just yet. And while we should avoid class variables, class methods are a very important part of Ruby. Finally, we aren't building complex applications that use inheritance so we also don't have to worry too much about subclasses being polluted.

A class variable can be called anywhere in a class. Here's an example:

class Album
  @@albums = []
end

Lesson 9 of 37
Last updated August 7, 2022