CanCan accessbly_by在规范和控制器中返回不同的响应



我正在尝试测试Farm模型的用户身份验证,在这种情况下,:user角色在登录时具有读取访问所有农场(作为guest用户aka)。

# /models/ability.rb
class Ability
  include CanCan::Ability
  def initialize(user)
    # Create guest user aka. anonymous (not logged in) when user is nil.
    user ||= User.new
    if user.has_role? :admin
      can :manage, :all
    else # guest user aka. anonymous
      can :read, :all
      # logged in user
      if user.has_role? :user
        can :create, Farm
        can :manage, Farm, :user_id => user.id
      end
    end
  end
end

# /controllers/api/v1/farms_controller.rb
class Api::V1::FarmsController < ActionController::Base
    load_and_authorize_resource
    rescue_from CanCan::AccessDenied do |exception|
        redirect_to farms_path, alert: exception.message
    end
    respond_to :json
    def index
        # Next line might be redundant refering to the CanCan wiki. See below..
        @farms = Farm.accessible_by(current_ability, :read)
        respond_with(@farms)
    end
end

# /spec/api/v1/farm_spec.rb
require "spec_helper"
describe "/api/v1/farms" do
    let(:user) { create(:user) } # lets call this user1 in the discussion
    let(:token) { user.authentication_token }
    before do
        user.add_role :user
        create(:farm, user: user, name: "Testfarm")
        create(:farm, name: "Access denied")
        @ability = Ability.new(user)
    end
    context "farms viewable by this logged-in user" do
        let(:url) { "/api/v1/farms" }
        it "json" do
            get "#{url}.json"
            farms_json = Farm.accessible_by(@ability, :read).to_json
            assert last_response.ok?
            last_response.body.should eql(farms_json)
            last_response.status.should eql(200)
            farms = JSON.parse(last_response.body)
            farms.any? do |farm|
                farm["name"] == "Testfarm"
            end.should be_true
            farms.any? do |farm|
                farm["name"] == "Access denied"
            end.should be_true
        end
    end
end
<标题>

当我检查farms_json时,我可以看到它包含 Testfarm。当我检查last_response时,我可以看到它包含 Testfarm Access denied。这很奇怪,因为我在规范和index操作中使用了相同的accessible_by方法。我使用的设置在CanCan gem的wiki中描述为"抓取记录"。

无用的解决方法

当我将用户user添加到农场Access denied时,例如…

create(:farm, user: user, name: "Access denied")

…测试成功。

<标题>
  1. 为什么"Access denied"farm 返回,尽管它可以被任何用户(包括guest用户)读取?
  2. get "#{url}.json"是否考虑了用户的状态?这一切都是由load_and_authorize_resourceFarmsController完成的吗?
  3. wiki提到@farms = Farm.accessible_by(current_ability, :read)可以省略,因为"这是由load_resource自动完成的索引操作"。这适用于我的情况吗?
<标题> 实验

我创建了另一个用户user2和另一个农场My little farm。我把它们连在一起。这样,示例中的数据库总共包含三个农场:

  • 与user1关联的农场Testfarm
  • 农场"Access denied"不关联任何用户
  • 与user2关联的农场"My little Farm"

当我运行Farm.accessible_by(Ability.new(user1), :read)时,我仍然只收到"Testfarm"

我的问题的答案由多个部分组成。我希望这对其他处理类似配置的人澄清了设置。

<标题> 1。能力优先h1> 先请注意,能力规则的顺序很重要,如能力优先级所述。在意识到这个事实之后,我想出了一套更新的能力规则。
# /models/ability.rb
class Ability
  include CanCan::Ability
  def initialize(user)
    # Create guest user aka. anonymous (not logged-in) when user is nil.
    user ||= User.new
    if user.has_role? :admin
      can :manage, :all
    else
      # logged in user
      if user.has_role? :user
        can :manage, Farm, :user_id => user.id
        can :create, Farm
      end
       # guest user aka. anonymous
      can :read, :all
    end
  end
end
<标题> 2。FarmsContoller h1> 索引操作中保持简单。load_and_authorize_resource是你的朋友。
# /controllers/api/v1/farms_controller.rb
class Api::V1::FarmsController < ActionController::Base
    load_and_authorize_resource
    rescue_from CanCan::AccessDenied do |exception|
        redirect_to farms_path, alert: exception.message
    end
    respond_to :json
    def index
        respond_with(@farms)
    end
end
<标题> 3。获取带有身份验证令牌的请求

当您从农场控制器请求数据时,不要忘记传递令牌。

# # /spec/api/v1/farm_spec.rb
get "#{url}.json", auth_token: :token

该令牌必须按如下方式添加到User模型中。

# app/models/user.rb
class User < ActiveRecord::Base
    before_save :ensure_authentication_token

方法的名称可以在设计的初始化器中配置。

# config/initializers/devise.rb
config.token_authentication_key = :auth_token

相关内容

  • 没有找到相关文章

最新更新