Nithin Bekal

Posts About Notes Slides

When to Use Protected Methods in Ruby

23 Oct 2014

The protected method visibility in Ruby is one of its more confusing aspects. I recently took a closer look at it, and found that it has an interesting use case.

First let’s take a quick look at how public and private method visibility works.

class Foo
  def hello
    'Hello'
  end

  private
  def secret
    'abracadabra'
  end
end

foo = Foo.new
foo.hello     #=> 'Hello'
foo.secret    #=> NoMethodError

Here, calling foo.hello works, but the private method can’t be called outside the scope of the class. Private methods can only be called implicitly - you cannot specify the object on which the method is being called.

class Foo
  def leak
    puts secret        #=> 'abracadabra'
    puts self.secret   #=> NoMethodError
  end

  private
  def secret
    'abracadabra'
  end
end

In the code above, #leak calls the secret method correctly, but self.secret doesn’t work, because you’re explicitly setting the receiver of the method.

In case of protected methods, you can call them from the scope of any object belonging to the same class. This means that when you pass a Person object p1 as an argument to a method on another Person object p2, you can access all the protected methods of p1 within that method.

class Person
  def older_than?(other_person)
    age > other_person.age
  end

  protected
  def age
    @age
  end
end

In the above example, the #older_than? method needs to access other_person’s age, but we don’t want age to be public. When age method is protected, foo.older_than?(bar) works as long as bar belongs to Person class or any of its subclasses (ie. bar.is_a?(Person) is true).

I don’t remember ever having to use protected in all these years, but it’s good to finally know where it could be used.

Further reading

Hi, I’m Nithin Bekal, a software craftsman with over 7 years of experience in shipping web applications. I mostly use Ruby, but lately have also been exploring Elixir. Co-founder of CrowdStudio.in, and helping organize Rubyconf India. Tweet to me at @nithinbekal.