开发者

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... :)

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜