Ramy
Ramy

Reputation: 21261

access control tripping me up

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.

Upvotes: 0

Views: 103

Answers (1)

Batkins
Batkins

Reputation: 5706

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..

Upvotes: 1

Related Questions