简体   繁体   中英

CanCan::AccessDenied with factory_girl and cancan, How correctly to write the factory?

I am suffering for the third day, I can not understand why I do not pass the next test:

 4) Error:
ArticlesControllerTest#test_should_get_index_if_admin:
CanCan::AccessDenied: You are not authorized to access this page.
    test/controllers/articles_controller_test.rb:22:in `block in <class:ArticlesControllerTest>'

What am I doing wrong? help me please!

I have got old application (rails 4.2), with many fixtures data.

I try migrate my test environment from fixtures to factory_girl. So I'm new to this.

Now I'm using:

  • cancancan + devise
  • factory_girl + TestCase

My articles controller:

class ArticlesController < ApplicationController
  load_and_authorize_resource
  before_filter :authenticate_user!, except: [:show]

  def index
    @articles = Article.paginate(page: params[:page], per_page: 10).includes(:translations)
  end
end

Ability.rb:

Class Ability
 include CanCan::Ability

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

   # Everybody
   can :show, [Article]

   if user.admin?
     can :manage, Article
   end
 end
end

My factory article.rb is very simple:

FactoryGirl.define do
 factory :article do
   content "MyText"

   factory :one_article
   factory :two_article
 end
end

My factory user.rb is simple too:

FactoryGirl.define do
  factory :user do
    sequence(:email) { |n| "user#{n}@mail.ru" }
    password "password"
    password_confirmation "password"
    after(:create) {|u| u.roles_mask = 4}
    profile

    factory :valid_admin do
      first_name "Administrator"
      last_name "Administrator"
      association :profile, factory: :admin_profile
      after(:create) {|u| u.roles_mask = 2}
    end
  end
end

My articles controller test:

require 'test_helper'

class ArticlesControllerTest < ActionController::TestCase
  include Devise::Test::ControllerHelpers

  setup do
    @article = create(:one_article)
    @admin   = create(:valid_admin)
  end

  test 'should get index if admin' do
    sign_in @admin

    ability = Ability.new(@admin)
    assert ability.can? :index, Article

    get :index
    assert_response :success
    assert_not_nil assigns(:articles)
  end
end

Info by pry:

[1] pry(#<ArticlesControllerTest>)> sign_in @admin
=> [[20709], "9BET5RWNuJPrGHUFi86d"]
[2] pry(#<ArticlesControllerTest>)> ability = Ability.new(@admin)
=> #<Ability:0x0000000c3c5ff8
 @rules=
  [#<CanCan::Rule:0x0000000c3c5f80
    @actions=[:show],
    @base_behavior=true,
    @block=nil,
.............<<Many lines>> ..............
[3] pry(#<ArticlesControllerTest>)> assert ability.can? :index, Article
=> true
[4] pry(#<ArticlesControllerTest>)> get :index
CanCan::AccessDenied: You are not authorized to access this page.
from /home/da/.rvm/gems/ruby-2.2.6@wenya/gems/cancancan-1.16.0/lib/cancan/ability.rb:217:in `authorize!'

Thanks in advance for your help!

This are the devise guideline, you need to create a method to log in the user as admin. This is the login_method you need to create

Controller tests (Test::Unit)

To sign in as admin for a given test case, just do:

class SomeControllerTest < ActionController::TestCase
  # For Devise >= 4.1.1
  include Devise::Test::ControllerHelpers
  # Use the following instead if you are on Devise <= 4.1.0
  # include Devise::TestHelpers

  def setup
    @request.env["devise.mapping"] = Devise.mappings[:admin]
    sign_in FactoryGirl.create(:admin)
  end
end

Note: If you are using the confirmable module, you should set a confirmed_at date inside the Factory or call confirm! before sign_in.

Here is the basics to prepare inside your Factory:

FactoryGirl.define do
  factory :account do
    email { Faker::Internet.email }
    password "password"
    password_confirmation "password"
    confirmed_at Date.today
  end
end

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM