Search code examples
ruby-on-railsruby-on-rails-4rspeccancan

how testing ability for joins tables?


please help solve the problem. i use gem 'cancan' and join tables for roles hierarchy. schema:

create_table "roles", force: :cascade do |t|
  t.string   "name",       limit: 255
end

create_table "roles_users", id: false, force: :cascade do |t|
  t.integer "role_id", limit: 4
  t.integer "user_id", limit: 4
end

create_table "users", force: :cascade do |t|
  t.string   "email",                  limit: 255, default: "", null: false
  t.string   "encrypted_password",     limit: 255, default: "", null: false
end

i have 3 roles: table roles:

id        name
0         user
1         manager
2         admin

i create 3 users and i gave them roles: table roles_users:

role_id         user_id
2               2
1               3
0               1

ability.rb:

class Ability
  include CanCan::Ability
  def initialize(user)
    user ||= User.new # guest user (not logged in)

    if user.role? :admin
      can :manage, :all
      cannot :update, Review
    elsif user.role? :manager
      can :read, Review
      can :create, Review
      can :update, Review
      cannot :delete, Review
    elsif user.role? :user
      can :read, Review
      can :create, Review      
      cannot :update, Review
      cannot :delete, Review
    else
      can :read, Review
      cannot :create, Review
      cannot :update, Review
      cannot :delete, Review
    end   
  end   
end   

factory:

FactoryGirl.define do
  factory :user do
    sequence(:email){ |i| "us#{i}@ad.ad" }
    password 'qwertyui'
    password_confirmation{ |u| u.password }    
  end 
end

FactoryGirl.define do
  factory :admin_status, class: Role do
    role_id 2
    user_id 2
  end

  factory :manager_status, class: Role do
    role_id 1
    user_id 3
  end

  factory :user_status, class: Role do
    role_id 0
    user_id 1
  end

end

i need testing ability for admin user via r spec:

require 'rails_helper'

RSpec.describe Review, type: :model do
  before(:each) do
    @user = FactoryGirl.create(:user) #create admin
    @ability = Ability.new(@user)
  end

  it "cannot delete review" do
    expect(@ability).to be_able_to(:delete, Review)
  end  
end

but after run test console display follow error message:

kalinin@kalinin ~/rails/admin_book $ rspec spec/models/review_spec.rb
F
Failures:
  1) Review cannot delete review
     Failure/Error: expect(@ability).to be_able_to(:delete, Review)
       expected to be able to delete Review
     # ./spec/models/review_spec.rb:11:in `block (2 levels) in <top (required)>'

please help check permission delete review for admin user


Solution

  • From fast review it looks like your assumption about roles IDs are not correct.

    But actually, I think, you are doing it wrong.

    If role is nothing more then name, and you explicitly use those names in your code, what's the reason to create roles table?

    I would recommend to use roles as string values: "admin", "manager" etc. With this setup you don't need to guess what roles IDs are and I hope it will help your tests too (assuming you have no other errors then this).