Protect your privates

Joe Ferris

''

When you write little helper methods in your controllers, do you use protected or private? Do you know why?

Pop quiz: what will this sample print out?

class Parent
  def mr_public
    'public'
  end

  def access_other_protected(other)
    other.mr_protected
  end

  def access_other_private(other)
    other.mr_private
  end

  def access_self_protected
    self.mr_protected
  end

  def access_self_private
    self.mr_private
  end

  protected

  def mr_protected
    'protected'
  end

  private

  def mr_private
    'private'
  end
end

class Child < Parent
  def access_parent_protected
    mr_protected
  end

  def access_parent_private
    mr_private
  end
end

def attempt
  puts yield
rescue
  puts 'forbidden'
end

parent = Parent.new
other = Parent.new
child = Child.new

attempt { parent.mr_public  }
attempt { parent.mr_protected  }
attempt { parent.mr_private  }

attempt { parent.access_self_protected  }
attempt { parent.access_self_private  }

attempt { parent.access_other_protected(other)  }
attempt { parent.access_other_private(other)  }

attempt { child.access_parent_protected  }
attempt { child.access_parent_private  }

Answer:

public
forbidden
forbidden
protected
forbidden
protected
forbidden
protected
private

What the hell just happened

Some lesser-known rules:

  • A child class can invoke private methods defined on its parent
  • A class cannot invoke private methods on itself if you use self
  • A class cannot access private methods an another instance of its own class

Some guidelines:

  • Define almost everything as private instead of protected!
  • You essentially only need to use protected together with methods like ==, <, or >.

About thoughtbot

We've been helping engineering teams deliver exceptional products for over 20 years. Our designers, developers, and product managers work closely with teams to solve your toughest software challenges through collaborative design and development. Learn more about us.