views:

66

answers:

3

I have some records in my database which only the owning users, or administrators are allowed to view/edit etc.

What is the best way to secure these records on an application level so that only these people can see these records? I could do this manually with conditions, but I would need to ensure I use the same conditions on every single find().

Any ideas?

+2  A: 

I find the best way is to avoid finders on the actual model like this...

SecretRecord.find(:id, :conditions => 'user = ?', current_user.id)

and instead use the collections off the user object

class User
  has_many :secret_records
end

current_user.secret_records.find(id)

This automatically scopes the select to those secret records that belong to the current user.

  • I'm assuming that you have a variable called current_user of type User provided by your authentication system (such as restful_authentication)
hopeless
best example, right here!
Omar Qureshi
...and how do you handle administrators?
Neil Middleton
Hmmm... apologies, I missed the part about administrators.
hopeless
+3  A: 

Scoping a finder to the current_user is useful in most instances, but does not account for a user being an administrator and having access to objects to which it is not directly associated.

Create a named scope within the model to restrict the selection to records owned by the user or any if the specified user is an administrator. The User model must implement a method called "is_admin?" that returns true if the User is considered an admin.

This way you can call:

my_widgets = Widget.accessible_by(user).find(:all, :conditions => ["created_at > ?", 1.day.ago.to_s(:db)])

class Widget
  named_scope :accessible_by, lambda {|u|
      conditions = nil        
      unless u.is_admin?
        conditions = ["widgets.user_id = :user_id", {:user_id => u.id}]
      end
      return {:conditions => conditions}
    }
end
codeprimate
Is there some way to make the accessible_by always run. So you can just go with my_widgets = Widget.find(:all, :conditions => ["created_at > ?", 1.day.ago.to_s(:db)])
Guy C
+1  A: 

Put a filter in front of all controllers that can be used to access this information

current_user.admin? or params[:person_id].to_i == current_user.person.id

If this condition is not met redirect them somewhere else

nasmorn