1

tl;博士

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

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

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

谢谢。;-)

长版

你好世界,

我有一个单用户博客应用程序并使用CanCan进行授权。我希望管理员 ( user.admin? # => true) 能够为所欲为(他们毕竟是管理员……)。我还希望普通用户(登录但没有admin角色的用户和未登录的用户)能够查看已发布的博客文章。我不希望他们看到那些未发表的。

(模型的)博客文章Post都有一个名为(默认published_at为 aDateTime和)的属性。nil不用说:当published_at是时nil,帖子不发布,否则在设置的日期和时间发布。

我的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调用的模型实例:@postPostsController#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中删除调用PostsController,意识到它可能会覆盖某些功能或其他东西,但它没有帮助。

我想出了一个临时解决方案,尽管我觉得它很丑,并且真的很想利用 CanCan 的能力。我丑陋的临时解决方案在内部检查PostsController#show用户是否有权查看资源:

def show
  @post = Post.find params[:id]

  unless @post.published_at
    raise CanCan::AccessDenied unless current_user && current_user.admin?
  end

  respond_with @post
end

正如我所说,这行得通。但我真的不想采用这个解决方案,因为我相信有更好的方法来做这件事作为 CanCan 能力。

我非常感谢解释为什么我的方法不起作用以及解决问题的好方法。提前致谢。:-)

4

1 回答 1

0

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

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

在您的 Post 模型中

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
于 2012-05-07T11:50:47.890 回答