Rails: Dynamic :finder_sql possible?
My architecture looks like this (simplified): I've got users with different privileges that create posts that undergo a certain l开发者_StackOverflow中文版ifecycle (created, reviewed, closed, stuff like that...).
Speaking in rails terms, a class User has_many :posts
, but I want the users to see posts depending on their privileges. If a user is privileged, he should be able to see all posts, if not I want him to see only posts that have already been reviewed plus all of his own posts.
Right now, the Post model has a class method for_user(user)
that simply checks the users privileges and returns the according posts. I understand, that's probalby not the Rails-way to do that, and I was wondering if it could be done something like that:
class User
has_many :posts, :finder_sql => finder
#[...]
def finder
if self.has_privileges? #simplified...
all
else
where( '[...]' )
end
end
Unfortunately, this doesn't work as rails expects the :finder_sql to be a string and a string only. Is there any other way to create the desired behaviour?
I'm doing something very similar in my current application, and I've found that using CanCan makes it very easy.
Granted, it might take a bit more effort to move your privileges logic over to CanCan, but it does add a lot of flexibilty. If nothing else, you could have a look at the source to see how he does it.
One possible way is to create an alias method "all_posts" and then define your own posts method that uses it:
class User
has_many :all_posts, :class_name => "Post"
def posts
self.has_priviledges? ? self.all_posts : self.all_posts.where(...)
end
end
This has the disadvantage of losing some of the caching ActiveRecord does for you. For instance, if you called user.all_posts twice, only the first would call sql, but calling user.posts twice could possibly call sql both times if the where clause is used.
Rather than using a has_many
association (which adds a bunch of setter methods, as well as getters), simply define a method (which you've more or less already done):
def User < ActiveRecord::Base
has_many :posts # written by the user
# Posts the user can see
def posts_visible_to
if has_privileges?
Post.all
else
posts
end
end
end
PS you spelled 'privileges' wrongly... :)
精彩评论