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: