Method visibility in Ruby (public, protected, and private methods) has been well explained in places like this blog post. But in Ruby on Rails it seems slightly different than it would be in a regular Ruby application because of the way the framework is set up. So, in Rails models, controllers, helpers, tests, etc., when is/isn't it appropriate to use protected or private methods?
Edit: Thanks for the answers so far. I understand the concept of protected and private in Ruby, but I'm looking more for an explanation of the typical way those types of visibility are used within the context of the various pieces of a Rails app (models, controllers, helpers, tests). For example, public controller methods are action methods, protected methods in the application controller are used for "helper methods" that need to be accessed by multiple controllers, etc.
You seem to have a good idea of the semantics of class visibility (public/protected/private) as applied to methods. All I can offer is a quick outline of the way I implement it in my Rails apps.
I implement protected methods in the base application controller so they can get called by any controller via filters (e.g. before_filter :method_foo). In a similar way, I define protected methods for models that I want to use in all of them in a base model that they all inherit from.
Although actions need to be public methods of a controller, not all public methods are necessarily actions. You can use
hide_action
if you're using a catch-all route like/:controller/:action/:id
or if it's disabled (the default in Rails 3) then only methods with explicit routes will be called.This can be useful if you're passing the controller instance to some other library like the Liquid template engine as you can provide a public interface rather than having to use send in your Liquid filters and tags.
http://en.wikibooks.org/wiki/Ruby_Programming/Syntax/Classes#Declaring_Visibility
For models, the idea is that the public methods are the public interface of the class. Public methods are intended to be used by other objects, while protected/private methods are to be hidden from the outside.
This is the same practice as in other object-oriented languages.
For
controllers andtests, just do as you please.Both controller andtest classes are only instantiated and called by the framework (yes, I know you can theoretically get the controller from the view, but if you do that, something is strange anyway). Since no one will ever create those things directly, there's nothing to "protect" against.Addendum/Correction: For controllers, you should mark the "helper" methods as
protectedprivate, and only the actions themselves should be public. The framework will never route any incoming HTTP calls to actions/methods that are not public, so your helper methods should be protected in that way.For helpers it will make no difference if a method is protected or private, since they are always called "directly".
You can mark stuff protected in all those cases if it makes things easier for you to understand, of course.
You use a private method if you want no one else but
self
to use a method. You use a protected method if you want something onlyself and is_a?(self)
s can call.A good use of protected might be if you had a "virtual" initialization method.
@foo will have different values. and the Derived instances will not have @baz
Update: Since I wrote this, some things have changed in Ruby 2.0+ Aaron Patterson has an excellent write up http://tenderlovemaking.com/2012/09/07/protected-methods-and-ruby-2-0.html