Канкан не показывает авторизованные элементы представления - PullRequest
2 голосов
/ 28 сентября 2010

Я пытаюсь получить базовую аутентификацию / авторизацию с помощью devise / cancan с Rails.Вместо того, чтобы использовать роли, такие как скринкаст Райана Б. и другие примеры, я пытаюсь сделать что-то простое:

1 - пользователь может войти в систему
2 - пользователь может редактировать / уничтожать только свои собственные статьи (без ролей, вы либо вошли в систему и можете создавать новые статьи и редактировать / уничтожать свои собственные, либо вы вышли из системы и можете видеть только статьи и вход в систему)

Я использую devise для первой частии это работает хорошо, но я не могу заставить вторую часть работать с CanCan.Ссылки на редактирование и уничтожение статей не отображаются, когда вы вошли в систему, и прямой URL (например, / article / 3 / edit) по-прежнему разрешается, даже если статья предназначена для другого пользователя.

Myability.rb is

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 не работает.Как я упоминал выше, это также не ограничивает реальные действия, так как вы можете напрямую ссылаться на редактирование статьи, и это позволяет.

Я не уверен, что я делаю здесь неправильно,Было бы здорово получить помощь.

Заранее спасибо
Джейсон

Ответы [ 3 ]

2 голосов
/ 30 сентября 2010

Мне удалось решить мою проблему.Я перезапустил свою среду (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 для ссылки на текущую статью в списке в _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 голос
/ 28 сентября 2010

Ваше условие для соответствия идентификатору пользователя не совсем правильно. Должно быть:

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

Атрибут, который вы хотите проверить, сопоставлен со значением, которое вы хотите проверить.

Кроме того, вы проверяете user.nil?, когда оно не может быть равно нулю, потому что вы только что его инициализировали. (Вероятно, симптом того, что много чего перепробовал!)

0 голосов
/ 28 сентября 2010

Ваш улов работает? Если вы раскомментируете can: manage,: всю строку, сможет ли пользователь редактировать свой пост (вместе со всеми, конечно)?

Вы пытались изменить, можете: управлять, статья,: user_id == пользователь на

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

Мне никогда не удавалось загрузить разрешение на работу, хотя я подозреваю, что я что-то делал не так. Чтобы запретить кому-либо доступ к URL-адресу напрямую, попробуйте добавить это

в действие редактирования вашей статьи.
 unauthorized! if cannot? :edit, @article
...