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
Why can I access private/protected methods using Object#send in Ruby?
Technically: Because send
doesn't do anything to check method visibility. (It would be more work to do so.)
Philosophically: Ruby is a very permissive language. You can already just open up a class and make any method you want public. The language designers implemented send
in a way that allows it to override the restrictions normally imposed by private
. Ruby 1.9 was originally going to have two variants, a private
-respecting send
and an unsafe variant called send!
, but this was apparently dropped for backwards compatibility.
As for what private
, protected
and public
mean:
public
methods can be called by any senderprotected
methods cannot be called outside of an instance of the method's class or an instance of a subclassprivate
methods cannot be called with an explicit receiver (with a couple of exceptions, such as setter methods, which always have to have an explicit receiver, and so can be called within the class that way)
Why does ruby allow child classes access parent's private methods?
The difference is that in ruby you can call private methods in subclasses implicitly but not explicitly. Protected can be called both ways. As for why? I guess you would have to ask Matz.
Example:
class TestMain
protected
def say_hola
puts "hola"
end
def say_ni_hao
puts "ni hao"
end
private
def say_hi
puts "hi"
end
def say_bonjour
puts "bonjour"
end
end
class SubMain < TestMain
def say_hellos
# works - protected/implicit
say_hola
# works - protected/explicit
self.say_ni_hao
# works - private/implicit
say_hi
# fails - private/explicit
self.say_bonjour
end
end
test = SubMain.new
test.say_hellos()
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.
Protected and Private methods
protected methods (or atributes) can only be used by the classes that inherit the class with protected methods (or atributes).
a d
\ \
b e
\
c
If the class a have a protected method, this can be used by b and c, but can't be used by d or e.
Note: Ascii art diagram for inherit in ruby classes.
class A
public
def f obj
obj.c
end
def g obj
obj.b
end
def call_b
b
end
private
def b
puts "Hi!_b"
end
protected
def c
puts "Hi!_c"
end
end
a = A.new
b = A.new
a.f(b) # Hi!_c
a.g(b) # inj.rb:7:in `g': private method `b' called for #<A:0xb76df4cc> (NoMethodError)
a.call_b # Hi!_b
In this case, the method f can 'see' the protected method because its of the same class (or an inherited one), but the private method encapsulate(hides) the 'b' method of all the cases, except if this is called inside of his class (by another accesible method (in this case, the method call_b)).
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.
Related Topics
Error: While Executing Gem ... (Gem::Filepermissionerror)
Does Ruby Have Real Multithreading
Code Block Passed to Each Works With Brackets But Not With 'Do'-'End' (Ruby)
Why How to Refer to a Variable Outside of an If/Unless/Case Statement That Never Ran
Installing Bootstrap 3 on Rails App
Gem Installation Error: You Have to Install Development Tools First (Windows)
Rescue_From Actioncontroller::Routingerror in Rails 4
Paginating an Array in Ruby With Will_Paginate
Validation for Non-Negative Integers and Decimal Values
What Is Ruby'S Double-Colon '::'
How to Sum Array of Numbers in Ruby
Difference Between Include and Require in Ruby
How to Set Tls Context Options in Ruby (Like Openssl::Ssl::Ssl_Op_No_Sslv2)
Ruby Function to Remove All White Spaces
Why Does String Interpolation Work in Ruby When There Are No Curly Braces