Baking role conditions into association proxies

0 views
Skip to first unread message

steveluscher

unread,
Mar 3, 2009, 3:20:49 PM3/3/09
to Rails Authorization Plugin
I've found myself foregoing foreign key associations between a user
and a model in favor of associating them through roles. Now, though, I
find that I miss association proxies!

Let's say a User can have many Images and vice versa. Normally you
might do this:

class User < ActiveRecord::Base
has_and_belongs_to_many :images
end

class Image < ActiveRecord::Base
has_and_belongs_to_many :users
end

create_table :images_users, :id => false do |t|
t.integer :user_id, :image_id
t.timestamps
end

But instead, I've been creating each model in isolation and
associating them by giving the user a "role" with respect to the
image, like this:

class User < ActiveRecord::Base; end
class Image < ActiveRecord::Base; end

>> u = User.create
>> i = Image.create
>> u.is_owner_of i

>> u2 = User.create
>> i2 = Image.create
>> u2.is_fan_of i2

Now, of course, I find myself wishing that I could do stuff like this:

>> u.images # Returns an association proxy for images for which u has any role at all
>> u.images.find_by_caption('Christmas 2008') # Association proxy finder, only for images for which u has a role

>> u.images.which_accept_fan_role # Returns an association proxy for images for which u has the 'fan' role
>> u.images.which_accept_fan_role.find_by_caption('Christmas 2008') # Association proxy finder, only for images for which u has the 'fan' role

…but I can't begin to imagine how to go about the implementation.

Is there any merit to this idea?

Cheers,
Steve…

steveluscher

unread,
Mar 5, 2009, 4:27:28 AM3/5/09
to Rails Authorization Plugin
Getting a little closer…

class Image < ActiveRecord::Base
acts_as_authorizable
named_scope :governed_by, lambda {|*args| user, role = args
if !role.blank?
conditions = ['roles_users.user_id = ? AND roles.id = ?', user,
role] if role.is_a? Role
conditions = ['roles_users.user_id = ? AND roles.name = ?',
user, role] if role.is_a? String
else
conditions = ['roles_users.user_id = ?', user]
end
{:include => :accepted_roles, :joins => 'LEFT OUTER JOIN
roles_users ON `roles`.id = role_id', :conditions => conditions}
}
end

class User < ActiveRecord::Base
def images; Image.governed_by(self); end
def owned_images; Image.governed_by(self, 'owner'); end
def favorite_images; Image.governed_by(self, 'fan'); end
end

>> u.images # Returns an array of images for which the user "u" has any role at all
>> u.owned_images # Returns an array of images for which the user "u" has the 'owner' role
>> u.favorite_images # Returns an array of images for which the user "u" has the 'fan' role
>> u.favorite_images.find_by_medium('photography') # Ouch! Not so association proxy-y!
ActiveRecord::StatementInvalid: Mysql::Error: Unknown column
'roles.id' in 'on clause': SELECT DISTINCT `images`.id FROM `images`
LEFT OUTER JOIN roles_users ON `roles`.id = role_id WHERE
(`images`.`medium` = 'photography') AND (roles_users.user_id = 1)
LIMIT 1
Reply all
Reply to author
Forward
0 new messages