Protected and private methods in 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.
Rails Private vs. Protected?
can you have private and protected in a single Ruby on Rails controller?
Yes, you can. Rails controllers are just classes, and classes can have any number and combination of private
and protected
blocks.
Use protected
if you want to allow for inherited controllers to access the method. Use private
if you want the method to be accessible only by the controller itself.
When to use private method in Rails?
In the Rails ActionController context, public methods of a controller class are exposed to web server through Rails routes. You can define a route to the public methods of the class and use them as controller actions.
However you can not define routes to private methods. They are designed as internal helper methods and there is no way to expose them to web server.
This leads to a basic convention in your controllers: Define each of your controller action as a public method, define routes for each of them and ether define views corresponding the actions or chain each action to another action or view. Use private methods or other classes for your helper methods or other components.
Of course these are conventions. You can make all your methods in controllers public if you're sure that no one would define routes to these methods or exposing them to the clients won't be harmful (as exposing sensitive information, creating vulnerability or just looking silly).
Why does Ruby have both private and protected methods?
protected
methods can be called by any instance of the defining class or its subclasses.
private
methods can be called only from within the calling object. You cannot access another instance's private methods directly.
Here is a quick practical example:
def compare_to(x)
self.some_method <=> x.some_method
end
some_method
cannot be private
here. It must be protected
because you need it to support explicit receivers. Your typical internal helper methods can usually be private
since they never need to be called like this.
It is important to note that this is different from the way Java or C++ works. private
in Ruby is similar to protected
in Java/C++ in that subclasses have access to the method. In Ruby, there is no way to restrict access to a method from its subclasses like you can with private
in Java.
Visibility in Ruby is largely a "recommendation" anyways since you can always gain access to a method using send
:
irb(main):001:0> class A
irb(main):002:1> private
irb(main):003:1> def not_so_private_method
irb(main):004:2> puts "Hello World"
irb(main):005:2> end
irb(main):006:1> end
=> nil
irb(main):007:0> foo = A.new
=> #<A:0x31688f>
irb(main):009:0> foo.send :not_so_private_method
Hello World
=> nil
Rails using private and protected methods in a Service object
You have an extra end
after def execute..end
. That end closes the CreateService
class. This means your protected methods are defined on the Store
module.
Hence the missing method.
Using private and protected methods in one controller in Rails
To simply answer your question: yes, when you have the following code:
private
....
protected
....
Then private stops where protected begins.
Why can method defined as private on ApplicationController be called inside methods of derived class but not inside the derived class itself?
The method you define in ApplicationController
is an instance method. As such, it can be called from within another instance method of a derived controller. Here:
class UserController < ApplicationController
@cart = current_cart
you are attempting to call it in the class definition, not in an instance method of the class, so it's looking for a class method, which doesn't exist.
As for being able to call a private method in a derived controller, see for example Protected and private methods in Rails.
EDIT: From http://en.wikibooks.org/wiki/Ruby_Programming/Syntax/Classes#Declaring_Visibility:
In Ruby, “private” visibility is similar to what “protected” is in Java. Private methods in Ruby are accessible from children. You can’t have truly private methods in Ruby; you can’t completely hide a method.
Related Topics
Oo Design in Rails: Where to Put Stuff
Ruby: What Does 'Require: False' in Gemfile Mean
Why Doesn't Ruby Support Method Overloading
How to Set Tls Context Options in Ruby (Like Openssl::Ssl::Ssl_Op_No_Sslv2)
What Are All the Common Ways to Read a File in Ruby
What's the Difference Between Uri.Escape and Cgi.Escape
How to Create Multiple Submit Buttons For the Same Form in Rails
No Increment Operator (++) in Ruby
How to Install Sqlite3 For Ruby on Windows
Difference Between Collection Route and Member Route in Ruby on Rails
What Are the Ruby Gotchas a Newbie Should Be Warned About
Cannot Install Json Gem in Rails Using Windows
Error: Failed to Build Gem Native Extension on Mavericks
Printing the Source Code of a Ruby Block