3

我正在尝试使用带有 Rails 的 devise/cancan 获得一些基本的身份验证/授权。我没有使用像 Ryan B 的截屏视频和其他示例这样的角色,而是尝试做一些基本的事情:

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, :all,甚至can :manage, Article不起作用。正如我上面提到的,它也不会限制实际操作,因为您可以直接链接到编辑文章并且它允许这样做。

我不确定我在这里做错了什么。能得到一些帮助会很棒。

提前感谢
杰森

4

3 回答 3

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>

现在都在工作。感谢您在这里的帮助,希望如果他们遇到这个问题,这将帮助其他人。

于 2010-09-30T04:23:30.520 回答
1

您匹配用户 ID 的条件不太正确。它应该是:

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

您要检查的属性映射到您要检查的值。

此外,您正在检查user.nil?它何时不能为 nil,因为您刚刚对其进行了初始化。(可能是尝试了很多东西的症状!)

于 2010-09-28T09:02:13.890 回答
0

你的捕捞有用吗?如果您取消注释 can :manage, :all 行,用户将能够编辑他/她的帖子(当然还有其他人的帖子)?

您是否尝试过更改,可以 :manage, Article, :user_id == user to

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

我一直无法获得工作授权——尽管我怀疑我做错了什么。为防止某人直接访问该网址,请在您文章的编辑操作中尝试添加此

 unauthorized! if cannot? :edit, @article
于 2010-09-28T18:10:11.497 回答