I have a Rails 3.2 app with Devise and CanCan. User abilities are defined by roles. There are five Roles in the database with id values 1-5, and a User has_one role through a Membership. So, for example, Membership.create(user_id: 2, role_id: 4)
will lead to User.find(2).role == Role.find(4) # => true
My ability file looks like
if user.has_role? :admin
can :manage, Model
can :manage, AnotherModel
# etc.
elsif user.has_role? :basic
can :read, Model
can :read, AnotherModel
elsif user.has_role? (etc. for other roles)
(etc.)
else
cannot :manage, :all
I want to kick out people who are attempting to access pages they are not authorized for. My application controller includes:
rescue_from CanCan::AccessDenied do |exception|
reset_session
redirect_to new_user_session_path
end
This behavior works properly when clicking around in development—-a basic user created via rails console gets kicked out when trying to do admin things, and a user with no roles (created in console, then User.last.membership.destroy
so that User.last.role # => nil
) cannot log in to the dashboard--instead the user is immediately redirected to the login page (a User with no role cannot manage anything).
I'm having problems when trying to test this same behavior, specifically for users with no role:
# spec/support/login_helpers.rb
def login_via_sign_in_page(user)
visit new_user_session_path
fill_in :user_email, with: user.email
fill_in :user_password, with: user.password
click_button 'Sign in'
end
# spec/features/dashboard_spec.rb
describe "as a user with no role" do
let(:user) { FactoryGirl.create(:user) }
before { login_via_sign_in_page(user) }
it "should redirect to the sign_in page" do
current_path.should == new_user_session_path
end
end
The above test fails, with RSpec showing that the user successfully made it to the dashboard page instead of being redirected to the sign in page. However, the following specs do pass:
# spec/features/dashboard_spec.rb
describe "as a guest browser (no login whatsoever)" do
it "should redirect to the sign_in page" do
visit dashboard_index_path
current_path.should == new_user_session_path
end
end
describe "as an admin user" do
let(:user) { FactoryGirl.create(:admin_user) }
before { login_via_sign_in_page(admin_user) }
it "should go to the dashboard" do
visit dashboard_index_path
current_path.should == dashboard_index_path
end
end
...as well as things like basic user getting redirected to the sign_in page when attempting admin actions
I have read this post, which seems to be dealing with a similar issue, but the suggestions there have not helped.
Finally, I get confusing results when using debugger
and save_and_open_page
. The former will give me user # => <A legit User object>
and user.role # => nil
. However, save_and_open_page
shows me logged in on the dashboard page.