0

Just wondering if there's a better way to do the following:

Users has_many Projects

Projects has_many lists

Lists has_many Items

Certain users only have access to certain projects. But if a user has access to a project, then the user can access all the lists and items belonging to that project.

Here's a method that I want to clean up:

def check_for_user_access(resource, resource_class, user)
  case resource_class
    when 'Project'
      if resource.user == user
        return true
      end
    when 'List'
      if resource.project.user == user
        return true
      end
    when 'Item'
      if resource.list.project.user == user
        return true
      end
    else
      return false
  end
end

I didn't want a user_id attribute in List and Item since access is really just tied to Project.

Is there a better way to do this than with a switch statement to wrap around the slightly different comparison?

Thanks in advance!

Zhao Li
  • 4,936
  • 8
  • 33
  • 51

2 Answers2

1

Perhaps a simpler way to do this is to define a allow_access? method for each of those resource classes – then all the controller has to do is ask the resource if the user's allowed in. For example:

class Project < ActiveRecord::Base #I assume
  def allow_access?(user)
    return self.user == user
  end
end

class List < ActiveRecord::Base
  def allow_access?(user)
    return self.project.user == user
  end
end

class Item < ActiveRecord::Base
  def allow_access?(user)
    return self.list.project.user == user
  end
end

And, optionally, put a wrapper in your User model:

class User < ActiveRecord::Base
  def can_access?(resource)
    resource.allow_access?(self)
  end
end

And then your method can be replaced with

user.can_access?(resource)

If you wanted to tighten things up a bit, your User model could check to see if the resource responds to allow_access? and react appropriately if it doesn'tâ€Ĥ

andrewdotnich
  • 16,195
  • 7
  • 38
  • 57
0

Two things:

1) Given your situation I would consider adding a belongs_to :user on Lists and Items, since it looks like they can only belong to one user.

Having this duplicated in your list and item models isn't going to hurt anything, and it will give you a significantly simpler way to see who any given object in your app belongs to.

2) You should check out CanCan. It's a really simple and lightweight Authorization library which is designed to regulate access to things just like you're dealing with.

Andrew
  • 42,517
  • 51
  • 181
  • 281
  • I'm worried about adding another belongs_to since it might lead to a scenario where the information might get disjointed (ie project belongs to one user and one of its list belongs to another). It shouldn't happen, but I didn't want to have to check for it. Thanks for the suggestion on CanCan. I was actually trying to write the ability rule for it, but that tip would definitely have been helpful if I hadn't known about it. It's such a lifesaver. Thanks for sharing your thoughts! – Zhao Li Apr 25 '12 at 00:10
  • Just FWIW you can fairly easily validate to ensure it is not `disjointed`, but I'm glad you found a solution you like. – Andrew Apr 25 '12 at 01:54