Protected and private methods in Rails

Ruby on-RailsRubyVisibilityPrivateProtected

Ruby on-Rails Problem Overview


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.

Ruby on-Rails Solutions


Solution 1 - Ruby on-Rails

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 and tests, just do as you please. Both controller and test 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 protected private, 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.

Solution 2 - Ruby on-Rails

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 only self and is_a?(self) s can call.

A good use of protected might be if you had a "virtual" initialization method.

class Base
    def initialize()
        set_defaults()
        #other stuff
    end

    protected
    def set_defaults()
        # defaults for this type
        @foo = 7
        calculate_and_set_baz()
    end

    private
    def calculate_and_set_baz()
        @baz = "Something that only base classes have like a file handle or resource"
    end
end

class Derived < Base
    protected
    def set_defaults()
        @foo = 13
    end
end

@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

Solution 3 - Ruby on-Rails

> The difference between protected and > private is subtle. If a method is > protected, it may be called by any > instance of the defining class or its > subclasses. If a method is private, it > may be called only within the context > of the calling object---it is never > possible to access another object > instance's private methods directly, > even if the object is of the same > class as the caller. For protected > methods, they are accessible from > objects of the same class (or > children).

http://en.wikibooks.org/wiki/Ruby_Programming/Syntax/Classes#Declaring_Visibility

Solution 4 - Ruby on-Rails

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.

Solution 5 - Ruby on-Rails

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.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionjrdiokoView Question on Stackoverflow
Solution 1 - Ruby on-RailsaverellView Answer on Stackoverflow
Solution 2 - Ruby on-RailsEnabrenTaneView Answer on Stackoverflow
Solution 3 - Ruby on-RailsnunopoloniaView Answer on Stackoverflow
Solution 4 - Ruby on-RailsSashaView Answer on Stackoverflow
Solution 5 - Ruby on-RailspixeltrixView Answer on Stackoverflow