RESTful ACL Question (get an error author not found)

Hi everybody,

hope somebody can help me. I always get this error, even every relation is set in the models:

NameError Exception: undefined local variable or method `author'

as soon as I do something like this, it works... (when I debug, I don't have access to the actual instance attributes, either the relations)

this works

this works --------------- def self.is_readable_by(user, object = nil) true if user.eql?(object.author) || user.admin end

instead of (manual, wiki of RESTful_ACL) -------------------------------------------------------------- def self.is_readable_by(user, object = nil) true if user.eql?(author) || user.admin end

...is that a bug, or am I doing something wrong here? can it be done easier?

hi,

first of all, from your code i understand that you have a class called "object". This should really be avoided since there already is a class called object (the ruby core class, that is), so you will actually reopen the ruby object-class.

to your question: you have to specifiy the object either with self.author or object.author. that's the only way as far as i know...

i hope this helps! smn

I don't see an indication of there being a class named "Object." Yes there is a local variable named "object."

What I can't see from the code in the OP is what kind of object is being passed into the method referred to by "object." If this is an ActiveRecord object containing an association to an "Author" object then you would need object.author. user.eql?(author) would be attempting to refer to a local variable named "author" which doesn't exist.

I'm also guessing that this method might be defined in an ActiveRecord subclass and you are expecting to be able to access the "author" method directly. If that's the case then you should realize that "self.is_readable_by(...)" is a class method so you wouldn't want to try to access an instance method such as the "author" association. This is why an object instance is being passed into the class method.

I am also making the assumption that the object passed into "object" has an association to an Author object, which appears to be the case since your solution works.

The issue is that you're defining your method as a class method, not an instance method; i.e, you should do

def is_readable_by(user)

not

def self.is_readable_by(user)

This is because author is an instance method, and so is not reachable from class methods.

I'm skimming the surface of class vs. instance methods so if you need more details, just let me know.

Jeff softiesonrails.com purpleworkshops.com

I have to admit that Ruby's use of the "self" keyword to define class methods feels a bit awkward to me. However, that's probably because I learned Objective C before diving into Ruby. Objective C uses the "self" keyword to mean "this instance" in a similar way as Java uses the "this" keyword. It was just a matter of getting used to it.

I personally like the syntax of the Objective C language where you would have something like this:

+ myClassMethod {   // implementation }

- myInstanceMethod {   // implementation }

Methods with plus signs are class methods, where methods with minus signs are instance methods. This way to intent is explicit and clear. Class and instance methods are treated with the same "respect" in a way.

But, at the end of the day it's all just all semantics.

so it is really, like that, the object has to be called. so I take it like I figured out: object.author

thanks all for your help!

Rafael

I personally like the syntax of the Objective C language where you would have something like this:

+ myClassMethod { // implementation

}

- myInstanceMethod { // implementation

}

The Ruby use of self is a bit more complicated. It's closer to java that it appears that you understand. It refer to the current object in a similar way to java, it's just that when you are in the context of a class definition, self happens to refer to the class that is being defined. You could just as easily declare it this way if it's easier to understand:

class MyClass   def MyClass.my_class_method   ...   end

  def self.my_other_class_method   ...   end end

The flexibility of self in Ruby permits some other useful things. For example, look at how ActiveRecord spins up getters and setters for db- backed attributes. It hooks method_missing and then uses 'self' (which in this context refers to the current instance) to as the receiver for setter/getter definitions.

I think the confusion arises because the 'def self.bar' use of self for declaring class methods is one of the most common uses.

Jeff Cohen wrote:

The issue is that you're defining your method as a class method, not an instance method; i.e, you should do

def is_readable_by(user)

not

def self.is_readable_by(user)

Just to clarify why RESTful_ACL defines the is_readable_by method as a Class-level method...

This method is responsible for securing both object#index and object#show. Since object#index operates on a set of objects, it needs to be class level. On the other hand, since it also secures object#show (one object), it needs to have access to a potential object, hence (object = nil)

Hope this clarifies :wink:

If you really want to grok this, read the chapter on 'self' in Ruby for Rails. The trippy things (for me) were realizing that 1) in addition to being blueprints for creating objects (instances), ruby classes are objects in their own right, and 2) class definitions are *executed*.

You can also play with this:

# ========================= puts("In open code: self is now #{self}")

def top_level_method   puts("In top_level_method: self is now #{self}") end

top_level_method

class MyClass   puts("In MyClass: self is now #{self}")

  def MyClass.my_class_method     puts("In MyClass.my_class_method: self is now #{self}")   end

  def my_instance_method     puts("In my_instance_method: self is now #{self}")   end end

MyClass.my_class_method

fred = MyClass.new

fred.my_instance_method # =========================

I'm not sure what's behind the idiom for using 'self' in class method definitions. I guess it makes it easier if you later want to rename the class. :wink: