Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

Already on GitHub? Sign in to your account

" CanCan::AccessDenied" error in rspec #461

Closed
railsfactory-dhibika opened this Issue Aug 31, 2011 · 15 comments

Comments

Projects
None yet
2 participants

My rspec code for "listing controller"

describe "GET :edit" do
before(:all) do
# Necessary because Spree automatically makes the first user
# created an Admin, and in the contexts below we want non-admins
# so that we test the authorizations
User.create!(Factory.attributes_for(:user))
end

let(:product) { Factory(:daily_deal) }

context "for a logged-in User" do
  context "that is the creator of the product being edited" do
    before(:each) do
      sign_in product.creator
      get :edit, :id => product.id.to_s
    end

    it { should respond_with(:ok) }
    it { should render_template(:edit) }
  end

  context "that is not the creator of the product being edited" do
    before(:each) do
      sign_in Factory(:user)
    end

    it "raises an authorization error" do
      expect { get :edit, :id => product.id.to_s }.to raise_error(CanCan::AccessDenied)
    end
  end

end

context "for a non-logged-in User" do
  it "raises an authorization error" do
    expect { get :edit, :id => product.id.to_s }.to raise_error(CanCan::AccessDenied)
  end
end

end

code in "listing controller"

def edit
render :template => @product.daily_deal? ? 'listings/edit_daily_deal' : 'listings/edit_gift_card'
end

It show error as follows

ListingsController GET :edit for a logged-in User that is not the creator of the product being edited raises an authorization error
Failure/Error: expect { get :edit, :id => product.id.to_s }.to raise_error(CanCan::AccessDenied)
expected CanCan::AccessDenied but nothing was raised

Reply me if anyone knows

nimf commented Aug 31, 2011

what is your ability.rb?

I am overriding the ability.rb like this.

module OneDesignCompany
class AbilityDecorator
include CanCan::Ability

def initialize(user)
  can(:create, Product) if user.can_sell?

  can :update, Product do |product|
    user == product.creator
  end

  can :destroy, Product do |product|
    user == product.creator
  end
end

end
end

Ability.class_eval { register_ability OneDesignCompany::AbilityDecorator }

nimf commented Sep 5, 2011

Is there load_and_authorize_resource or other authorization method in listing or application controller? Or may be edit action is excluded from authorization? Did it pass for non-logged-in User?

In my listing controller

load_and_authorize_resource :class => Product, :instance_name => "product", :only => [:new, :edit, :destroy]

nimf commented Sep 5, 2011

did you try to replace :only => [:new, :edit, :destroy] with :except => :index? because you would probably need it for :update

Let me try

Now also i am getting error:

In my listing_controller_spec the full code is below:

require 'spec_helper'

describe ListingsController do
describe "GET :new" do
context "for a User who can sell" do
let(:user_who_can_sell) { Factory(:user_who_can_sell) }

  before(:each) do
    sign_in user_who_can_sell
    get :new
  end

  it { should respond_with(:ok) }
  it { should render_template(:new) }

  it "builds a daily deal into @daily_deal" do
    assigns(:daily_deal).daily_deal?.should be_true
  end

  it "builds an address for the daily deal" do
    assigns(:daily_deal).address.should_not be_nil
  end

  it "builds a gift card into @gift_card" do
    assigns(:gift_card).gift_card?.should be_true
  end
end

context "for a non-logged-in User" do
  it "raises an authorization error" do
    expect { get :new }.to raise_error(CanCan::AccessDenied)
  end
end

end

describe "DELETE :destroy" do
before(:all) do
# Necessary because Spree automatically makes the first user
# created an Admin, and in the contexts below we want non-admins
# so that we test the authorizations
User.create!(Factory.attributes_for(:user))
end

let(:product) { Factory(:daily_deal) }

context "for a logged-in User" do
  context "that is the creator of the product being destroyed" do
    before(:each) do
      sign_in product.creator
      delete :destroy, :id => product.id.to_s
    end

    it "makes the specified Product deleted" do
      product.reload.deleted?.should be_true
    end

    it { should redirect_to(my_listings_path) }
  end

  context "that is not the creator of the product being destroyed" do
    before(:each) do
      sign_in User.create!(Factory.attributes_for(:user))
    end

    it "raises an authorization error" do
      expect { delete :destroy, :id => product.id.to_s }.to raise_error(CanCan::AccessDenied)
    end
  end

end

context "for a non-logged-in User" do
  it "raises an authorization error" do
    expect { delete :destroy, :id => product.id.to_s }.to raise_error(CanCan::AccessDenied)
  end
end

end

describe "GET :edit" do
before(:all) do
# Necessary because Spree automatically makes the first user
# created an Admin, and in the contexts below we want non-admins
# so that we test the authorizations
User.create!(Factory.attributes_for(:user))
end

let(:product) { Factory(:daily_deal) }

context "for a logged-in User" do
  context "that is the creator of the product being edited" do
    before(:each) do
      sign_in product.creator
      get :edit, :id => product.id.to_s
    end

    it { should respond_with(:ok) }
    it { should render_template(:edit) }
  end

  context "that is not the creator of the product being edited" do
    before(:each) do
      sign_in Factory(:user)
    end

    it "raises an authorization error" do
      expect { get :edit, :id => product.id.to_s }.to raise_error(CanCan::AccessDenied)
    end
  end

end

context "for a non-logged-in User" do
  it "raises an authorization error" do
    expect { get :edit, :id => product.id.to_s }.to raise_error(CanCan::AccessDenied)
  end
end

end

describe "GET :index" do
it "includes the current latitude and longitude in the params when instatiating a Searcher" do
get :index

  controller.params[:location].should == controller.send(:current_lat_and_lon)
end

end
end

In my listing controller:

class ListingsController < Spree::BaseController
helper :taxons, :products
load_and_authorize_resource :class => Product, :instance_name => "product", :except=>:index
before_filter :set_location_in_params, :only => :index

def new
build_daily_deal
build_gift_card
end

def index
@searcher = Spree::Config.searcher_class.new(params)
@products = @searcher.retrieve_products
@featured_products = featured_products.limit(100).shuffle[0..15]
c = @featured_products.size
if c < 15 and c > 12
@featured_products = @featured_products[0..11]
elsif c < 12 and c > 8
@featured_products = @featured_products[0..7]
elsif c < 8 and c > 4
@featured_products = @featured_products[0..3]
end
end

def edit
render :template => @product.daily_deal? ? 'listings/edit_daily_deal' : 'listings/edit_gift_card'
end

def destroy
@product.update_attribute(:deleted_at, Time.now)
redirect_to my_listings_path
end

private
def set_location_in_params
params[:location] = current_lat_and_lon
end

def unauthorized
render :template => "listings/cannot_sell" and return if current_user.present?
super
end
end

The rspec error for the listing spec is :

Failures:

  1. ListingsController GET :new for a non-logged-in User raises an authorization error
    Failure/Error: expect { get :new }.to raise_error(CanCan::AccessDenied)
    expected CanCan::AccessDenied but nothing was raised

    ./spec/controllers/listings_controller_spec.rb:31

  2. ListingsController DELETE :destroy for a logged-in User that is not the creator of the product being destroyed raises an authorization error
    Failure/Error: expect { delete :destroy, :id => product.id.to_s }.to raise_error(CanCan::AccessDenied)
    expected CanCan::AccessDenied but nothing was raised

    ./spec/controllers/listings_controller_spec.rb:66

  3. ListingsController DELETE :destroy for a non-logged-in User raises an authorization error
    Failure/Error: expect { delete :destroy, :id => product.id.to_s }.to raise_error(CanCan::AccessDenied)
    expected CanCan::AccessDenied but nothing was raised

    ./spec/controllers/listings_controller_spec.rb:74

  4. ListingsController GET :edit for a logged-in User that is not the creator of the product being edited raises an authorization error
    Failure/Error: expect { get :edit, :id => product.id.to_s }.to raise_error(CanCan::AccessDenied)
    expected CanCan::AccessDenied but nothing was raised

    ./spec/controllers/listings_controller_spec.rb:106

  5. ListingsController GET :edit for a non-logged-in User raises an authorization error
    Failure/Error: expect { get :edit, :id => product.id.to_s }.to raise_error(CanCan::AccessDenied)
    expected CanCan::AccessDenied but nothing was raised

    ./spec/controllers/listings_controller_spec.rb:114

Finished in 65.01 seconds
15 examples, 5 failures

Failed examples:

rspec ./spec/controllers/listings_controller_spec.rb:30 # ListingsController GET :new for a non-logged-in User raises an authorization error
rspec ./spec/controllers/listings_controller_spec.rb:65 # ListingsController DELETE :destroy for a logged-in User that is not the creator of the product being destroyed raises an authorization error
rspec ./spec/controllers/listings_controller_spec.rb:73 # ListingsController DELETE :destroy for a non-logged-in User raises an authorization error
rspec ./spec/controllers/listings_controller_spec.rb:105 # ListingsController GET :edit for a logged-in User that is not the creator of the product being edited raises an authorization error
rspec ./spec/controllers/listings_controller_spec.rb:113 # ListingsController GET :edit for a non-logged-in User raises an authorization error

nimf commented Sep 5, 2011

ok, can you, please, try with :only => [:new, :update, :destroy]?

If it will not work, then it seems it doesn't match :update with :edit, then go with:
:only => [:new, :edit, :update, :destroy]
and

can [:edit, :update, :destroy], Product do |product|
  user == product.creator
end

actually, it is better to compare just an ids.

Ok i will try

I tried according to your suggestion but same error still alives

nimf commented Sep 5, 2011

ok. when you try to edit as a non-logged-in user, what do you see in a browser and in log file?
May be exception get rescued somewhere?

Yes in browser when i edit as non-logged means it shows the partial file

render :template => "listings/cannot_sell" which is in unauthorized function

nimf commented Sep 5, 2011

Then may be you should check for this template to be used instead of checking AccessDenied to be raised?
What about other actions - did Rspec detect cancan AccessDenied exception? Is browser behavior same for them?

Thanks :) i use render template the error get resolved.

nimf commented Sep 5, 2011

Great! Then you can close this issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment