views:

703

answers:

2

Confession: I only use private and public visibility for my methods!

I have a feeling this is a bad thing. But in Rails it just doesn't seem to come up as an issue.

Does anyone have an example in Rails where it would be a big mistake not to use protected visibility?

A: 

I have SingleTableInheritance

class Person < AR::base class Teacher < Person calss Student < Person

And I use the protected methods to implement a private method that is common for Student and Teacher:

class Person < AR::base
  def self.find(*args)
    reject_leaves(super(*args))
  end
protected
  def self.reject_leaves(target) #like a private in Teacher and Student
    case target
      when Array target.select{|t| reject_leaves(t)}
      when Person (target.leave_date < Date.today ? target : nil)
      else target
    end
  end
end

Disclaimer: There are plugins like act-as-paranoid and other to implement the feature I use here to show you the case but I have a more complex landscape, that I have simplified here to get to your point.

Fer
fyi, your example above doesn't work correctly -- you can call `Person.reject_leaves(...)` without a problem. 'public/protected/private' in ruby are not keywords -- they are method invocations on `self` that modify the state of `self`. Since you change what `self` is when you do `def self. reject_leaves` you no longer have the `protected` state set up. to get what you want you'd need something like the second example (`Prot2`) here: http://pastie.org/842952
Jordan Brough
+3  A: 

Update -- Please see the comment below that links to a true explanation of protected/private in Ruby. That was a deep seated prejudice left over from my Java days, indeed. The only important part left to my answer is that controller methods that are not actions should not be public (or at least your routes should protect them).

Single Table Inheritance is a perfect example of when protected is helpful in the model tier, as it's one of the most common uses of inheritance there.

In the controller tier, helper methods defined on ApplicationController should be marked as protected -- if they were private the other controllers would not be able to access them, but if they are public Rails will treat them as actions.

Personally, I find that I use class inheritance more than many of my friends and coworkers, even in Rails applications. Because I use it often (and coming out of my Java days), I favor protected for all helper methods to give freedom to anyone (usually myself) who wants to extend the class -- unless I'm really really embarrassed about one, then I mark it private. :)

Ian Terrell
That makes a lot of sense. (Not sure what STI is though).
pez_dispenser
edited to expand STI :)
Ian Terrell
"helper methods defined on ApplicationController should be marked as protected -- if they were private the other controllers would not be able to access them" -- fyi, this is incorrect. See example here: http://pastie.org/842898 . Protected/private in Ruby is about 'self' and receivers, not inheritance. "Note that, unlike languages such as Java, inheritance plays absolutely no part in determining method visibility in Ruby." -- http://weblog.jamisbuck.org/2007/2/23/method-visibility-in-ruby
Jordan Brough
Thanks, Jordan. You're right. I've added a little note.
Ian Terrell