named_scopes

Hey all,

I'm learning rails and am trying to put together a generic ACL check
for all models. I've been able to sucessfully implement it as a
method for all models by decorating ActiveRecord::Base. But when I
try to do the "rails way" of creating an association (and thereby
taking advantage of the ORM), I don't get very far...

Here is the code:

class ActiveRecord::Base

  has_many(:permissions)
  named_scope(:acl_check, lambda do |user_id, method|
    {
      :include => :permission,
      :conditions => [
        ["permissions.user_id=?", user_id],
        ["permissions.method=?", method],
        ["permissions.classname=?", self.class.name]
      ]
    }
  end)

  # Conducts a permission check for the entire class.
  def self.check_acl(user_id, method)

    # Perform the permission check by User.
    permission_check =
Permission.find_by_user_id_and_instance_id_and_classname_and_method
(user_id, nil, self.class.name, method)
    if(permission_check)
      # If the row exists, we generate a hit.
      return(true)
    end

    # Perform the permission check by Role.

    # Otherwise, the permissions check was a miss.
    return(false)

  end

  # Conducts a permission check for the current instance.
  def check_acl?(user_id, method)

    # Perform the permission check by User.
    permission_check =
Permission.find_by_user_id_and_instance_id_and_classname_and_method
(user_id, self.id, self.class.name, method)
    if(permission_check)
      # If the row exists, we generate a hit.
      return(true)
    end

    # Perform the permission check by Role.

    # Otherwise, the permissions check was a miss.
    return(false)

  end

end

Currently, calling check_acl on either an instance of a model or the
model class itself functions as expected. But attempting to call
acl_check (my named_scope), just results in a method not found.

At the very least I'd like to know why this isn't working and if at
all possible, I'd like to hear some ideas on how I can make this
work. I've heard about using modules, but I'd like to not have to
include a source file in each model. Ideally doing it the object-
oriented way would make me happier :slight_smile:

But again, I'd love to hear details on why ActiveRecord isn't making
this happen....

Currently, calling check_acl on either an instance of a model or the
model class itself functions as expected. But attempting to call
acl_check (my named_scope), just results in a method not found.

So you're trying to call a named scope on an instance of your model ?
That won't work because named scopes aren't supposed to work that way.
In a nutshell scopes are about narrowing down the results of a find
(although they are also handy for adding other options to a find), eg
Person.active scopes the find to those people with active=true. When
you are just talking about a single object you have already loaded,
scopes don't make a lot of sense.

A fairly standard way of doing this would be to add a class method to
ActiveRecord::Base (eg acts_as_permissioned) and then calling that
method would add required associations and so on, so a model which
does use this stuff looks like

class Something < AR::Base
  acts_as_permissioned
end

(which at the end of the day is using modules and what not, but I find
this a whole lot clearer than having stuff inserted into the base
class. at least hear you have a clear statement at the top that this
class is using the permissions stuff)

Fred

(ps you probably don't want self.class.name in your self.check_acl
method, since this will always evaluate to 'Class' )