views:

55

answers:

2

I am using the sentient_user gem to have access to the current_user object in my application. I want to override the default ActiveRecordBase queries to scope them to the current user.

For instance, I don't want my users looking at, deleting, modifying other user's orders.

I feel like I should be able to override a single (or couple) ActiveRecordBase methods to accomplish this, but I don't know which or how.

Thanks in advance.

+3  A: 

In your controllers, use queries like:

@orders = current_user.orders.find(params[:id])

That'll scope the find query properly for you. You don't want to include code related to the current_user in your models or in ActiveRecord::Base - it violates MVC.

Edit: I should mention that when you need to do this in the model layer you'll use default_scope: http://ryandaigle.com/articles/2008/11/18/what-s-new-in-edge-rails-default-scoping

For example:

class Order < ActiveRecord::Base
  default_scope :order => 'created_at DESC', :conditions => { :processed => true }
end

Then, all Order queries will order by created_at descending, and only return records where processed = true, unless you override either of those options specifically.

PreciousBodilyFluids
Best not to use conditions with default scope, as if you negated the condition how would AR know which one was correct?
Ryan Bigg
+1  A: 

The main concern with default_scope is that it's not more in use when your chaining multiple scopes, so you can't put the logic of "scoping to the current user" in your models.

I believe that the genuine usage of AR associations (has_many :orders), should do the trick of retrieving only the orders related to the user performing action in your application.

If you want to secure your objects now, you could either use an authorization system (like ACL9) or implement your own like, in your case, putting in your model:

# Order model
class Order < AR::Base
  belongs_to :customer

  def is_allowed_to(action, performer)
    case action
      when 'show'
        performer.id == self.customer.id
      when 'update'
        performer.id == self.customer.id
      when 'destroy'
        performer.is_a? Administrator
      ....
  end
end

Then in your controllers that handle orders, you could use the before filter to retrieve the actual object in the DB and call the method is_allowed_to to check permissions. The action parameter would be either the actual action name or another one of your choice.

I hope it'll help.

Cesario