I created a starter app from RailsApps with the rails-devise-pundit example app. I am trying to write a user controller test because I plan to change some functionality and I want to make sure things still work. The pundit UserPolicy is not returning the correct value which is based on a role enum in the User class. The UserPolicy.index? method seen below is returning false when called from the first test in UsersControllerTest. Sorry there is a lot of code and detail here. I hope everyone can follow it.
Here's the failing test in UsersControllersTest. The response is a :redirect instead of :success.
require "test_helper"
class UsersControllerTest < ActionController::TestCase
def setup
@admin = users(:admin)
@admin.role = :admin
end
test "should get index page when authenticated as an admin" do
sign_in @admin
get :index
assert_response :success
end
...
end
Here's my user controller class just showing the index method where my problem is. authorize @users
should call the UserPolicy.index?
method.
class UsersController < ApplicationController
before_filter :authenticate_user!
after_action :verify_authorized, except: [:show]
def index
@users = User.all
authorize @users
end
...
end
My pundit user policy class. When I change the index?
method so it returns true, the response in my UsersControllerTest is :success. So for some reason @user.admin?
is not returning the correct value.
class UserPolicy
attr_reader :user, :record
def initialize(user, record)
@user = user
@record = record
end
def index?
@user.admin?
end
...
end
What is even stranger is that I created a UserPolicyTest class and when I test calling index?
from there, I get the correct response. This test works correctly:
require 'test_helper'
class UserPolicyTest < ActiveSupport::TestCase
def setup
@admin = users(:admin)
@admin.role = :admin
end
def test_index
policy = UserPolicy.new @admin, nil
assert policy.index?
end
end
Here is my User model:
class User < ActiveRecord::Base
devise :database_authenticatable, :registerable, :confirmable,
:recoverable, :rememberable, :trackable, :validatable
enum role: [:user, :vip, :admin]
after_initialize :set_default_role, :if => :new_record?
validates :name, presence: true
def set_default_role
self.role ||= :user
end
end
Here's my test fixture for an admin user:
admin:
email: [email protected]
name: Mr Admin
role: admin
encrypted_password: $2a$10$PoBe1MvkoGJsjMVTEjKqgeBUp.xdfzWoiDjBzQhtLAj16NqIa2fOy
remember_created_at: nil
sign_in_count: 3
current_sign_in_at: 2014-01-02 08:31:23
last_sign_in_at: 2014-01-02 08:31:23
current_sign_in_ip: 127.0.0.1
last_sign_in_ip: 127.0.0.1
confirmation_token: nil
confirmed_at: 2014-01-02 08:31:23
confirmation_sent_at: 2014-01-02 08:30:59
created_at: 2014-01-02 08:30:59
updated_at: 2014-01-02 08:31:23
I found that setting the role in the fixture doesn't work. I'm guessing that's because of the after_initialize :set_default_role, :if => :new_record?
line in my User model. If there's another reason or a better way to handle this, please let me know.
UPDATE: Maybe this is being caused by strong parameters. When I tried debugging my code with pry, I found that in the UsersControllerTest, after signing in, the admin user had a role of 2 which is correct. But when it got to User.Policy.index?, the role was 0. I may need to add the role field to the devise strong parameters. I saw something about how to do that a while back. It didn't look easy. If someone knows the answer before I get to it, please let me know.
After I changed the value of @admin.role in setup, I didn't save the user. After adding @admin.save to the setup method, the test passed.