access control tripping me up - ruby-on-rails

ok, i'm about at that point in my ruby career where this should be tripping me up.
I have a model called distribution.rb where I have the follwoing protected method:
def update_email_sent_on_date
if self.send_to_changed?
self.date_email_delivered = DateTime.now
end
end
I then call this method from my controller:
distribution.update_email_sent_on_date
however, I'm getting this error:
NoMethodError (protected method `update_email_sent_on_date' called for #<EmailDistribution:0x131a1be90>):
the distribution object is indeed an EmailDistribution (a subclass of distribution where the method is defined). I thought this would work. In any case, I also tried moving the method to the subclass EmailDistribution but no luck. Same error message.
I'd also like to step back and say that what I'm trying to do overall is store the timestamp of when another field in the distribution model is updated. If there's a simpler way, please enlighten me.

I think you're getting tripped up because you are using the protected declaration when you actually want the private declaration.
The protected term in ruby acts differently in other conventional languages.
In Ruby, private visibility is what protected was in Java. Private methods in Ruby are accessible from children. This is a sensible design, since in Java, when method was private, it rendered it useless for children classes: making it a rule, that all methods should be "protected" by default, and never private. However, you can't have truly private methods in Ruby; you can't completely hide a method.
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).
This is a slightly clearer explanation IMHO, from the book Eloquent Ruby by Russ Olsen:
Note that in Ruby, private methods are callable from subclasses. Think about it: You don't need an explicit object reference to call a superclass method from a subclass.
The rules for protected methods are looser and a bit more complex: Any instance of a class can call a protected method on any other instance of the class.
Lastly, it's good to note that in ruby you can always call private or protected methods regardless of whether they are accessible by using the send method. So if you were in a pinch and just needed to work you could just call it like this and then worry about the private/protected declarations later:
distribution.send(:update_email_sent_on_date)
Read this for more a better explanation..

Related

Calling private method in ApplicationController?

I am confused on how this library works:
The ApplicationController has a private method called selected_account() as you can see here: ApplicationController
Then, from another Controller which is a child from ApplicationController, we do an action that does this:
def index()
#selected_account = selected_account
graph = get_accounts_graph()
#accounts = Account.get_accounts_map(graph)
end
How can we do that? Isn't it out of scope?
This will be confusing for those who come from java or c# world. But here is a decent explanation
In Ruby, the inheritance hierarchy or the package/module don't really
enter into the equation, it is rather all about which object is the
receiver of a particular method call. When a method is declared
private in Ruby, it means this method can never be called with an
explicit receiver. Any time we're able to call a private method with
an implicit receiver it will always succeed. This means we can call a
private method from within a class it is declared in as well as all
subclasses of this class
It might be confusing at first, but in Ruby private does not mean what it means in Java/C++. Ancestors can call private methods just fine.
What private actually means is that you cannot call the method with an explicit target. That is, if foo is private, you can call it with foo(), but not with self.foo() or obj.foo(). That way you can call private methods only on yourself.
Furthermore, Ruby has protected. The semantics are again different from Java/C++ – protected methods can only be called from instances of the same class. It is rarely used.
The child controller inherits from ApplicationController so it can call internal private methods on itself without issue. There is no scoping problem. The subclass inherits all the public/private/protected methods of its super class.

Rails: what are the main reasons for making methods private?

If the end_user cannot access the source code of the app, why we still need to make some methods private?
I'm reading the Pragmatic Agile Web Development with Rails and I couldn't understand why we need to make the following method private (even after reading the explanation):
private
def current_cart Cart.find(session[:cart_id])
rescue ActiveRecord::RecordNotFound
cart = Cart.create
session[:cart_id] = cart.id
cart
end
end
It says that it will never allow Rails to make it available as an action, but as a coder, why would I ever do that myself?
As you say there may be no external reason to make it private. However, it also prevents you — or somebody else using your code — from accidentally making use of the method where you're not supposed to.
See it as a sanity check on your own future behaviour if you will.
It aims to encourage good practices and good code.
The idea is that you have two separate parts to your code:
"Above the line" (Public). This is the interface to the rest of the world. This is the API, where calls are made when using instances of the object. Once created, you know that THIS is the area where changes can affect current usages of the code.
"Below the line (Private). This is where detailed logic resides. This code can be changed and refactored freely without any affect to the public interface.
It may help guide your test writing
Private methods may or may not be (unit) tested.
Public methods are more encouraging of both unit and integrated tests as the fact that is is public means that it is serving as the public face for that code and as it is public it might be called from any other point in the future, so having good tests to make sure it continues to work as advertised is essential.
It may help with security as you have greater control who calls private methods (i.e. only public methods in the same class calling them).
It may help reduce name collisions as you have less names in the public space.
End user might not be able to access your code but someone else in your team can definitely access it and they might change it.
The other benefit of encapsulation is that it allows one class ("server") to make a contract with another class ("client") to provide some service with only a very few things being required to be known about the "server" class such as method signature and return type. The benefit is only realized if the contract of what is required and what is returned remains the same. So, in your example, there is no benefit since the contract was broken by Class A.
Instead of class A changing int type to float, class A should create another new variable of type float for other classes to use so that class B is not "broken" or that contract is not broken between them. Class C could refer to new float variable and Class B could still refer to old int variable and everyone is happy. Better yet, methods would used to retrieve values such as: "getUsersAddress" and "getUSersPhoneNumber" depending on what was wanted.
The real benefit of good encapsulation is that Class A can be completely re-written from top to bottom and as long as the contract is honored as to what Class A is expected to do(have methods "getUsersAddress" and "getUSersPhoneNumber"), then everything in Class B and C works the same. Think carefully about what is exposed and how it is exposed. Things that will change often and break other classes need to be considered carefully before exposing. Good encapsulation means hiding things that are expected to change often so to avoid breaking other classes.
It says that it will never allow Rails to make it available as an action,
Hmm, is this in a Rails Conroller class? And is the book you are working through written for Rails 2.x?
In Rails 2.x, by default any public method in a Controller can be triggered by someone accessing the url /name_of_controller/name_of_method .
But there are some methods in your controller that you don't want anyone on the web to trigger, they weren't intended as 'action methods'. So in Rails 2.x, you mark those as protected or private, something not public. "action method" means a method you intend to be directly triggered via a URL.
In Rails 3.x, routing has generally changed such that only certain methods you explicitly route to are available to be triggered via a URL. However, it might still make sense to mark non-action-methods in a Controller as protected or private so:
It's more clear from skimming the source which methods are action methods and which aren't
As a precaution in case someone changes the routing in such a way that would allow a URL to trigger those methods not intended as action methods
Or for general reasons of code organization that other answers mention, that are not specific to Rails controller classes.
There are several reasons as mentioned above. The interesting thing about this encapsulation in ruby is that it can be violated.
See the "send" method and its brother "public_send".
And for a very common metaprogramming technique that uses this method see:
dynamic finders

When should we consider using private or protected?

Just wondering, when should we actually must use private or protected for some methods in the model?
Sometimes I can't not be bothered to group my methods in private nor protected. I just leave it as it is. But I know it must be a bad practice, otherwise these 2 groupings won't be created in programming.
Thanks.
If you plan to call a method externally, record.method(), then "public"
If it will be used only internally, self.method(), then "private"
If you plan to use it internally, but also in descendants, self.method() # in subclass, then "protected"
I'll give my opinion, and maybe I'll get a kicking for it, but I don't bother with protected or private in Ruby. The reality is, Ruby treats you like an adult, if you want to run a private method from outside the class, you can (there are ways). You can run protected methods outside the class. You can even reassign constants... you can do whatever you like, basically.
And that's why I like it, it's your responsibility. My feeling is, that to mark something as protected or private you are doing two things:
Indicating that you don't think a consumer will need it.
Second guessing what someone else needs.
and in addition, you're making it harder to test, as it can be a real pain testing private methods (see What's the best way to unit test protected & private methods in Ruby? for ways around it)
For those last two reasons, I don't bother with them. If you really wanted some kind of barrier between your classes/methods and the consumers (be they code or developers) then there are other, more effective ways (proxies, obfuscation, encryption, password protected methods etc). Otherwise, why not give them access to the same tools you used?
I don't know Ruby as a special case, but I assume the answer would be the same as for other languages too, so here it is:
A private method can only be accessed by members of the same class, whereas a protected is also available for member of classes that extend the base class where the method is declared.

Sample Ruby code, How is this abstracting things out?

Watching this video by Yehuda, and he gave this snippet about how Ruby helps you build better abstractions.
class FOWA
def self.is_fun
def fun?
true
end
end
is_fun
end
He was talking about, in ruby, how if you are repeating code in your class over and over again, you can abstract it out without having to think about things in terms of methods etc. And he said this was using a metaprogramming technique.
Can someone explain what this is?
It is a class method on FOWA (so its like a static method, you don't need an instance to call it), and this class method is really just wrapping another method that returns true.
And this is_fun class method is now being executed or what? not sure what the last line "is_fun" is doing?
http://vimeo.com/11679138
The is_fun call at the end of the class calls the static method. The static method then defines the fun? method inside of the FOWA class. Then, you can do this:
f = FOWA.new
f.fun?
If you take out the is_fun call at the end of the class, the fun? method doesn't get defined.
He mentioned that you wouldn't use it in this way, but the point is how easy it is to dynamically add a method to a class. You might use it like this if you wanted the method to be available in subclasses and you wouldn't call is_fun in FOWA, but you might in a subclass. It gets a little more interesting if you have a parameter for is_fun and the definition of fun? changes depending on that parameter.
This also leads right into modules because you can define a module with the same is_fun method and then just have your class extend the module and the methods in the module are available in the class. You would use this technique if you want your method to be available to more than just subclasses of FOWA.

Long method and testing private methods - design problem

I have a quite long method. It copy an ActiveRecord object with all relations, and changes relations in some cases. To make code more readable, I use private methods. I would like to test them. Technicaly, in Ruby it is no problem, but I suspect, I have bad design. Do you have any advices how to deal with such case?
One school of thought is that each and every private method that matters should be tested implicitly by testing a class's public interface. If a private method didn't get called through the public interface, it is redundant. If your private method is that complex to require its own tests, you should consider putting it in a class of its own and test that class.
In short, it shouldn't be necesary to explicitly test your private methods.
as the saying go's: "Don't touch your privates."

Resources