Ruby on Rails - CanCan能够让管理员查看已发布的博客帖子

时间:2012-04-06 18:36:55

标签: authorization cancan ruby-on-rails-3.2

TL;博士

我在单作者博客中使用CanCan进行授权。我希望非管理员用户无法查看未发布的帖子。以下不起作用:

can :read, Post do |post|
  post.published_at && post.published_at <= Time.zone.now
end

为什么它不起作用,我该怎么做才能使它发挥作用?

感谢。 ; - )

长版本

Hello World,

我有一个单用户博客应用程序,并使用CanCan进行授权。我希望管理员(user.admin? # => true)能够随心所欲地做任何事情(毕竟他们是管理员......)。我还希望普通用户(包括已登录但没有admin角色的用户和未登录的用户)能够查看已发布的博客帖子。我不希望他们看到那些没有发表的内容。

博客帖子(模型Post)每个都有一个名为published_at的属性(默认为DateTimenil)。不用说:当published_atnil时,帖子不会发布,否则会在设定的日期和时间发布。

我的Ability课程中有以下内容:

class Ability
  include CanCan::Ability

  def initialize user
    user ||= User.new # guest user (not logged in)

    if user.admin?
      can :manage, :all
    else
      can :read, Post do |post|
        post.published_at && post.published_at <= Time.zone.now
      end
    end
  end
end

然而,这似乎并不像我想的那样有效。我已阅读CanCan wiki,这可能并不总是有效。但是,我认为它应该适用于我的情况,因为我在Post操作中有一个名为@post的{​​{1}}模型的实例:

PostsController#show

即使使用此代码,我也可以通过class PostsController < ApplicationController authorize_resource respond_to :html, :json # other actions omitted ... def show @post = Post.find params[:id] respond_with @post end # other actions omitted ... end 操作和视图访问博客文章。我还尝试从show删除authorize_resource来电,意识到它可能会覆盖某些功能或某些功能,但它没有帮助。

我已经找到了一个临时解决方案,虽然我发现它很难看并且真的想要利用CanCan的能力。如果用户有权查看资源,那么我丑陋的临时解决方案会在PostsController内部进行检查:

PostsController#show

正如我所说,这是有效的。但我真的不想采用这种解决方案,因为我相信有更好的方法可以做到这一点作为CanCan能力。

我非常感谢我解释为什么我的方法不能很好地解决问题。提前致谢。 : - )

1 个答案:

答案 0 :(得分:0)

在调用authorize_resource(before_filter)时,您没有要授权的帖子对象。

假设CanCan 1.6或更高版本,试试这个..

在你的帖子模型中

class Post < ActiveRecord::Base
  scope :published, lambda { where('published_at IS NOT NULL AND published_at <= ?', Time.zone.now) }
  # the rest of your model code
end

在你的能力模型中

class Ability
  include CanCan::Ability

  def initialize user
    user ||= User.new # guest user (not logged in)

    if user.admin?
      can :manage, :all
    else
      can :read, Post, Post.published do |post|
        post.published_at && post.published_at <= Time.zone.now
      end
    end
  end
end

在您的控制器中

class PostsController < ApplicationController
  load_and_authorize_resource
  respond_to :html, :json

  # other actions omitted ...

  def show
    respond_with @post
  end
end