1

tl; dr

単著ブログでの承認にはCanCanを使用しています。管理者以外のユーザーが未公開の投稿を表示できないようにしたい。以下はトリックを行いません:

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

なぜそれが機能しないのですか、そしてそれを機能させるために私は何ができますか?

ありがとう。;-)

ロングバージョン

こんにちは世界、

私はシングルユーザーのブログアプリケーションを持っており、承認の目的でCanCanを使用しています。管理者(user.admin? # => true)がすべてを使ってやりたいことができるようにしたいと思います(結局のところ、彼らは管理者です…)。また、通常のユーザー(ログインしているがadmin役割を持っていないユーザーとログインしていないユーザーの両方)が、公開されたブログ投稿を表示できるようにしたいと思います。公開されていないものを見せたくない。

(モデルの)ブログ投稿には、それぞれ(デフォルトではとPost)という属性があります。言うまでもなく、がの場合、投稿は公開されません。それ以外の場合は、設定された日時に公開されます。published_atDateTimenilpublished_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モデルのインスタンスがあるため、機能するはずです。@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) では、承認する投稿オブジェクトがありません。

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 に答える