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 >.