2012-04-06 7 views
1

tl zu lassen; dr

Ich benutze CanCan für die Zulassung in einem Single-Autor Blog. Ich möchte, dass Benutzer ohne Administratorrechte keine unveröffentlichten Posts anzeigen können. Das Folgende funktioniert nicht:Ruby on Rails - CanCan Fähigkeit, nur eine Admin Ansicht veröffentlichten Blog-Beiträge

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

Warum funktioniert es nicht, und was kann ich tun, damit es funktioniert?

Danke. ;-)

Die lange Version

Hallo Welt,

Ich habe eine Single-User-Anwendung Bloggen und CanCan Zulassungszwecke verwenden. Ich möchte, dass Administratoren (user.admin? # => true) mit allem machen können, was sie wollen (sie sind schließlich Administratoren ...). Ich möchte auch regelmäßige Benutzer (sowohl diejenigen, die angemeldet sind, aber nicht die admin Rolle, und diejenigen, die nicht angemeldet sind) in der Lage, Blogposts, die veröffentlicht wurden, zu sehen. Ich möchte nicht, dass sie diejenigen sehen, die nicht veröffentlicht sind.

Blog-Beiträge (des Modells Post) jeweils ein Attribut namens published_at (das ein DateTime und nil Standard). Unnötig zu sagen: Wenn published_atnil ist, wird der Beitrag nicht veröffentlicht, andernfalls wird er zum festgelegten Datum und Zeitpunkt veröffentlicht.

Ich habe folgendes in meiner Ability Klasse:

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 

Dies ist jedoch nicht zu funktionieren scheint, wie ich es zu beabsichtigen. Ich habe auf der CanCan wiki gelesen, dass dies nicht immer funktioniert. Aber ich glaube, es sollte hier in meinem Fall arbeiten, wie ich eine Instanz des @post in meiner PostsController#show Aktion aufgerufen Post Modells zu tun habe:

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 

Auch mit diesem Code: Ich kann die Blog-Post über die besuchen show Aktion und Ansicht. Ich habe auch versucht, den authorize_resource Anruf von der PostsController zu entfernen, realisierend, dass es einige Fähigkeiten oder etwas überschreiben könnte, aber es half nicht.

Ich habe eine temporäre Lösung gefunden, obwohl ich es hässlich finde und wirklich die CanCan-Fähigkeiten nutzen möchte. Meine hässliche temporäre Lösung prüft intern im PostsController#show wenn der Benutzer Zugriff hat, die Ressource zu lesen:

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 

Wie gesagt, das funktioniert. Aber ich möchte nicht wirklich mit dieser Lösung gehen, da ich glaube, dass es eine bessere Möglichkeit gibt, dies als CanCan-Fähigkeit zu tun.

Ich würde eine Erklärung dafür, warum mein Ansatz nicht so gut funktioniert, wie eine gute Lösung für das Problem, sehr schätzen. Danke im Voraus. :-)

Antwort

0

An dem Punkt, an dem authorize_resource aufgerufen wird (before_filter), haben Sie kein zu autorisierendes Post-Objekt.

Angenommen, CanCan 1.6 oder höher, versuchen Sie dies ..

In Ihrem Beitrag Modell

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 

in Ihrer Fähigkeit Modell

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 

In Ihrem Controller

class PostsController < ApplicationController 
    load_and_authorize_resource 
    respond_to :html, :json 

    # other actions omitted ... 

    def show 
    respond_with @post 
    end 
end