views:

32

answers:

1

Hi

I need to find an elegant solution to scoped finds based on access control rules. Essentially I have the following setup:

Users Customers AccessControl - Defines which user has access to another users data

Users need to be able to access not just their own customers but also shared customers of other users.

Obviously something like a simple association will not work:

has_many :customers

and neither will this:

has_many :customers, :conditions => 'user_id in (1,2,3,4,5)'

because the association uses with_scope and the added condition is an AND condition not an OR condition.

I also tried overriding the find and method_missing methods with the association extension like this:

has_many :customers do
  def find(*args)
    #get the user_id and retrieve access conditions based on the id
    #do a find based on the access conditions and passed args
  end 

  def method_missing(*args)
    #get the user_id and retrieve access conditions based on the id
    #do a find based on the access conditions and passed args
  end
end

but the issue is that I don't have access to the user object / parent object inside the extension methods and it just does not work as planned.

I also tried default_scope but as posted here before you can't pass a block to a default scope.

Anyhow, I know that data segmentation and data access controls have been done before using rails and am wondering if somebody found an elegant way to do it.

UPDATE: The AccessControl table has the following layout

user_id
shared_user_id

The customer table has this structure:

id
account_id
user_id
first_name
last_name

Assuming the the following data would be in the AccessControl table:

1  1
1  3
1  4
2  2
2  13
and so on...

And the account_id for user 1 is 13 I need to be able to retrieve customers that can be best described with the following sql statement:

select * from customers where (account_id = 13 and user_id = null) or (user_id in (1,3,4))
A: 

Sorry if I've completely missed the point here but I'm not 100% sure of what you want to do. Is AccessControl a relationship between User and Customer? If so looks like you just need to setup a many-to-many relationship.

class User
  has_and_belongs_to_many :customers   

  # or this if you need to store meta data in the join table 

  has_many :customers
  has_many :access_controls
  has_many :accessible_customers, through => :access_controls
end
tsdbrown
AccessControl is a relationship/join table between user and customers in my current design. However there is a small fly in the ointment:Customers data not only has to be scoped by the user id (in which case has_many through would work) but also by account_id (parent object of all users).The reason for this is this: once a user gets deleted the user_id on the customer object gets nulled and the restricting scope would fall back to account_id.The beast way to describe this is with sql:select * from customers where (account_id = 13 and user_id = null) or (user_id in (1, 3, 5, 6))
Rafael Szuminski