Contextual ActiveRecord模型过滤

时间:2009-04-24 17:01:19

标签: ruby-on-rails ruby activerecord authorization

在我们的网站中,有一个常见的模型,比如视频,它有许多属性,如私人/公共/待定,可下载等。

根据控制器,操作,请求参数和当前用户,我们希望从显示中过滤掉特定的视频。例如,在主页上我们只想显示公开的视频。如果主页上有登录用户,我们还希望显示公共可下载视频。

我们还希望确保这些过滤器可以单独通过sql查询应用,这样使用Sphinx时我们可以在用户在网站上搜索时过滤掉不需要的视频。

最好通过授权插件处理,例如rails-authorization-plugin?最重要的是,我们的目标是防止程序员在添加新操作时意外忘记过滤掉特定视频。我们正在寻找的解决方案应该是非常有条理的。

这是我正在考虑的解决方案(尚未编写任何代码)

  1. 使用authroization插件或滚动我们自己的插件,允许设置显示哪些视频,在控制器或操作级别定义。

  2. 为has_many(:videos)或has_one(:video)的任何模型创建关联扩展,这样我们就可以为关联中的视频重载查找器。

  3. 以类似的方式重载Video.find,以根据当前规则限制显示内容。

1 个答案:

答案 0 :(得分:3)

您的一般策略看似合理,但我强烈建议您不要覆盖rails默认查找器。相反,这是我过去做过的事情:

class Video < ActiveRecord::Base
  named_scope :available_to, lambda {|user|
    if user.nil?
      :conditions => {:public_accessible => true}
    elsif user.omnipotent?
      {}
    else 
      :conditions => [%{
        videos.public_accessible = ? OR EXISTS (
          ....boring security stuff linking to users....
        )
      }, true, user.id]
    end 
  }
end

然后在video_shop.rb中:

class VideoShop < ActiveRecord::Base
  has_many :videos 
end

最后,把它们放在一起:

# All videos available to a user
Video.available_to(user)

# All videos in a given shop
video_shop.videos

# All videos in a given shop available to a given user
video_shop.videos.available_to(user)

请注意,即使用户为零,这些也能正常工作。