2010-09-28 52 views
2

我試圖通過Rails的devise/cancan獲得一些基本的身份驗證/授權。而不是使用像Ryan B的截屏視頻和其他例子,我試圖做一些基本的事情:Cancan不顯示授權視圖元素

1 - 用戶可以登錄
2 - 用戶只能編輯/銷燬他們自己的文章(無角色,你要麼登錄,並可以創建新的文章和編輯/摧毀自己的或你已註銷,你只能看到文章和登錄)

我使用設計的第一部分,這是工作正常但我無法參與CanCan的第二部分工作。文章的編輯和銷燬鏈接在您登錄時不會顯示,並且直接的URL(例如/ articles/3/edit)仍然允許,即使該文章是針對其他用戶的。

ability.rb

class Ability 
    include CanCan::Ability 

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

    if user.nil? 
     can :read, :all 
    else 
#  can :manage, :all #test - with this, all the edit/destroy links appear 
     can :manage, Article, :user_id == user 
    end 
    end 
end 

articles_controller.rb

class ArticlesController < ApplicationController 

    before_filter :authenticate_user!, :except => [:index, :show] # for Devise 
    load_and_authorize_resource 


    # GET /articles 
    # GET /articles.xml 
    def index 

    @articles = Article.all 

    respond_to do |format| 
     format.html # index.html.erb 
     format.xml { render :xml => @articles } 
    end 
    end 

    # GET /articles/1 
    # GET /articles/1.xml 
    def show 
    @article = Article.find(params[:id]) 

    respond_to do |format| 
     format.html # show.html.erb 
     format.xml { render :xml => @article } 
    end 
    end 

    # GET /articles/new 
    # GET /articles/new.xml 
    def new 
    @article = Article.new 

    respond_to do |format| 
     format.html # new.html.erb 
     format.xml { render :xml => @article } 
    end 
    end 

    # GET /articles/1/edit 
    def edit 
    @article = Article.find(params[:id]) 
    end 

    # POST /articles 
    # POST /articles.xml 
    def create 
    @article = Article.new(params[:article]) 
    @article.user = current_user 

    respond_to do |format| 
     if @article.save 
     format.html { redirect_to(articles_path, :notice => 'Article was successfully created.') } 
     format.xml { render :xml => articles_path, :status => :created, :location => articles_path } 
     else 
     format.html { render :action => "new" } 
     format.xml { render :xml => @article.errors, :status => :unprocessable_entity } 
     end 
    end 
    end 

    # PUT /articles/1 
    # PUT /articles/1.xml 
    def update 
    @article = Article.find(params[:id]) 

    respond_to do |format| 
     if @article.update_attributes(params[:article]) 
     format.html { redirect_to(@article, :notice => 'Article was successfully updated.') } 
     format.xml { head :ok } 
     else 
     format.html { render :action => "edit" } 
     format.xml { render :xml => @article.errors, :status => :unprocessable_entity } 
     end 
    end 
    end 

    # DELETE /articles/1 
    # DELETE /articles/1.xml 
    def destroy 
    @article = Article.find(params[:id]) 
    @article.destroy 

    respond_to do |format| 
     format.html { redirect_to(articles_url) } 
     format.xml { head :ok } 
    end 
    end 
end 

和視圖部分列出的文章_article_list.html.erb

<table> 
     <tr> 
     <th>Title</th> 
     <th>Description</th> 
     <th>User</th> 
     <th></th> 
     <th></th> 
     <th></th> 
     </tr> 

    <% @articles.each do |article| %> 
     <tr> 
     <td><%= article.title %></td> 
     <td><%= article.description %></td> 
     <td><%= article.user_id %></td> 
     <td><%= link_to 'Show', article %></td> 
     <% if can? :update, @article %> 
      <td><%= link_to 'Edit', edit_article_path(article) %></td> 
     <% end %> 
     <% if can? :destroy, @article %> 
      <td><%= link_to 'Destroy', article, :confirm => 'Are you sure?', :method => :delete %></td> 
     <% end%> 
     </tr> 
    <% end %> 
    </table> 

有了這個設置,編輯/摧毀鏈接除非有毯子,否則視圖不會顯示,即使can :manage, Article也不起作用。正如我上面提到的,它也不會限制實際操作,因爲您可以直接鏈接到編輯文章並允許它。

我不知道我在做什麼錯在這裏。得到一些幫助是很好的。

在此先感謝
傑森

回答

2

我設法解決了我的問題。我重置了我的環境(rvm - 重新設置了gems和gemsets - ruby​​ 1.9.2和rails 3.0.0),並更改了一些代碼以及所有我離開時遇到的問題(重定向循環,根據記錄來查看元素不變在未授權的控制器操作仍然允許)。我粘貼了ability.rb,articles_controller.rb_article_list.html.erb

ability.rb

class Ability 
    include CanCan::Ability 

    def initialize(user) 
    if user 
     can :create, Article 
     can :read, :all 
     can :update, Article, :user_id => user.id 
     can :delete, Article, :user_id => user.id 
    else 
     can :read, :all 
    end 
    end 
end 

我想這是有道理的,但現在,因爲只有更新和刪除被認爲是當前用戶的文章中,我打出CRUD元素是具體的。

articles_controller.rb

class ArticlesController < ApplicationController 

    before_filter :authenticate_user!, :except => [:index, :show] 
# load_and_authorize_resource # RESTful automated CanCam authorization - excludes non RESTful 

    # GET /articles 
    # GET /articles.xml 
    def index 
    @articles = Article.all 
    authorize! :read, @articles 


    respond_to do |format| 
     format.html # index.html.erb 
     format.xml { render :xml => @articles } 
    end 
    end 

    # GET /articles/1 
    # GET /articles/1.xml 
    def show 
    @article = Article.find(params[:id]) 
    authorize! :read, @article 

    respond_to do |format| 
     format.html # show.html.erb 
     format.xml { render :xml => @article } 
    end 
    end 

    # GET /articles/new 
    # GET /articles/new.xml 
    def new 
    @article = Article.new 
    authorize! :create, @article 

    respond_to do |format| 
     format.html # new.html.erb 
     format.xml { render :xml => @article } 
    end 
    end 

    # GET /articles/1/edit 
    def edit 
    @article = Article.find(params[:id]) 
    authorize! :update, @article 
    end 

    # POST /articles 
    # POST /articles.xml 
    def create 
    @article = Article.new(params[:article]) 
    @article.user = current_user 
    authorize! :create, @article 

    respond_to do |format| 
     if @article.save 
     format.html { redirect_to(articles_path, :notice => 'Article was successfully created.') } 
     format.xml { render :xml => articles_path, :status => :created, :location => articles_path } 
     else 
     format.html { render :action => "new" } 
     format.xml { render :xml => @article.errors, :status => :unprocessable_entity } 
     end 
    end 
    end 

    # PUT /articles/1 
    # PUT /articles/1.xml 
    def update 
    @article = Article.find(params[:id]) 
    authorize! :update, @article 

    respond_to do |format| 
     if @article.update_attributes(params[:article]) 
     format.html { redirect_to(@article, :notice => 'Article was successfully updated.') } 
     format.xml { head :ok } 
     else 
     format.html { render :action => "edit" } 
     format.xml { render :xml => @article.errors, :status => :unprocessable_entity } 
     end 
    end 
    end 

    # DELETE /articles/1 
    # DELETE /articles/1.xml 
    def destroy 
    @article = Article.find(params[:id]) 
    @article.destroy 
    authorize! :delete, @article 

    respond_to do |format| 
     format.html { redirect_to(articles_url) } 
     format.xml { head :ok } 
    end 
    end 

    def by 
    @user = User.find(params[:id]) 
    @articles = @user.articles 
    authorize! :read, @articles 
    end 
end 

load_and_authorize_resource的作品,但我已經把具體的授權!在每個控制器行動中的行,因爲我有一個額外的行動在底部。兩者現在都有效。

我更新了參考@article到文章引用列表中的當前文章中_article_list.html.rb

<table> 
    <tr> 
    <th>Title</th> 
    <th>Description</th> 
    <th>User</th> 
    <th></th> 
    <th></th> 
    <th></th> 
    </tr> 

<% @articles.each do |article| %> 
    <tr> 
    <td><%= article.title %></td> 
    <td><%= article.description %></td> 
    <td><%= article.user_id %></td> 
    <td><%= link_to 'Show', article %></td> 
    <% if can? :update, article %> 
     <td><%= link_to 'Edit', edit_article_path(article) %></td> 
    <% end %> 
    <% if can? :delete, article %> 
     <td><%= link_to 'Destroy', article, :confirm => 'Are you sure?', :method => :delete %></td> 
    <% end %> 
    </tr> 
<% end %> 
</table> 

所有現在的工作。感謝這裏的幫助,希望這會幫助別人解決這個問題。

1

您的匹配用戶ID的條件是不完全正確。它應該是:

can :manage, Article, :user_id => user.id 

要檢查的屬性映射到您要檢查的值。

此外,您正在檢查user.nil?何時不能爲零,因爲您剛剛初始化它。 (可能是已經嘗試了很多東西的症狀!)

+0

感謝您的迴應Shadwell。是的,我確定在嘗試了許多不同的事情之後,現在有一些事情誤入歧途。我按照你的建議進行了調整,但仍然有相同的結果。我不知道它是否在說,但如果我做了長的形式,可以:manage,Article do | article | article.try(:user_id)== user.id end我得到錯誤「undefined method'user_id':index:Symbol」 – Jason 2010-09-28 12:17:20

0

您的接觸工作?如果取消註釋can:manage,:all line會讓用戶能夠編輯他/她的帖子(當然還有其他人的)?

您是否嘗試過改變,可以:管理,文章,:USER_ID ==用戶

can :manage, Article do |article| 
article.try(:user) == user 

我從來沒有能夠得到加載授權給工作 - 雖然我懷疑我是做錯了什麼。爲了防止有人直接訪問網址,請在文章的編輯操作中嘗試添加此

unauthorized! if cannot? :edit, @article 
+0

Thanks RobertH。是的,捕獲工程 - 編輯/銷燬登錄時顯示,登出時消失。我已經試過可以用上面顯示的塊,我得到和錯誤「未定義的方法'用戶'用於:編輯:符號」的細節從跟蹤說「app/models/ability.rb:14:in '初始化'中的塊。「 – Jason 2010-09-29 00:02:01

+0

我也嘗試刪除「load_and_authorize_resource」並在索引操作中指定「authorize!:read,@article」。瀏覽器然後報告重定向循環。不太確定我在這裏做錯了什麼。有沒有正式的CanCan支持論壇? – Jason 2010-09-29 00:05:52

+0

您是否嘗試粘貼代碼?我不知道爲什麼你會得到這樣的錯誤,因爲沒有使用「編輯」。此外,如果你不知道這個,這裏有一篇博客文章,告訴你如何用Devise設置CanCan http://www.tonyamoyal.com/2010/07/28/rails-authentication-with-devise-and -cancan-customizing-devise-controllers/ – RobertH 2010-09-29 03:05:11