Question

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: admin@example.com
  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.

Was it helpful?

Solution

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top