-1

I'm trying to use cancancan to disallow access to the sign-up page for non-members. Only members should be able to create new members. I defined by ability.rb, but I don't know how I can disallow the sign_up action. This is what I tries so far:

if user.has_role? :admin
else
  can :sign_in, User
  cannot :sign_up, User
  cannot :sign_up, Registration
  cannot :create, User
  cannot :create, Registration
end

But still I'm able to see the sign-up page without being logged in. Should I achieve this some other way? Or am I doing something wrong?

Thanks

bo-oz
  • 2,842
  • 2
  • 24
  • 44
  • cancancan ability declerations only defines roles. you need to check them for allowing or denying access. Have you done any checking at the sign-up page controller? – infiniteRefactor Jul 24 '16 at 20:10
  • No, I don't have that controller, probably Devise has. Do I need to overwrite it somehow? – bo-oz Jul 25 '16 at 04:41

2 Answers2

1

As @infiniteRefactor pointed out, CanCanCan restricts access based on role. Whether a user is logged in, on the other hand, is a matter of state (users can be logged in or logged out regardless of role). Luckily, you're already using Devise.

You can get what you want with the user_signed_in? helper method from Devise.

You can hide your sign up view by adding the following code to whatever view you're trying to hide:

<% if !(user_signed_in?) %>
    <%= redirect_to new_user_registration_path %>
<% else %>
    <!-- The rest of the view's code goes here -->
<% end %>

Then, to prevent the actual action when a user isn't signed in, make sure you're using:

before_action :authenticate_user!

in your controller.

MarsAtomic
  • 10,436
  • 5
  • 35
  • 56
  • I didn't mention I'm also using rolify to check and set roles to users. The basic idea is that not every user is allowed to add users. So, although I understand what you're saying, I do not a solution based on roles as well. Preferably from the same Ability model I use to set the other cancancan rules. – bo-oz Jul 25 '16 at 04:40
0

So you are trying to use the sign-up page of Devise and restrict the access to members only.

Devise only does authentication out of box. It's not aware of cancancan abilities or any other user logic you might have introduced. Thus, what you want won't work out of box.

You need to expose controllers and overwrite the sign-up controller. You can use

rails generate devise:controllers users

if your devise user schema is users. Please refer to devise documentation for the actual command reference. Then you can customize the registration controller.

What I'd prefer doing here would be using both ability and authentication checks as controller actions.

class Devise::RegistrationsController < DeviseController
    ...
    before_action :authenticate_user!
    load_and_authorize_resource

However you can do anything you want. That is the part you will want restrict the access. You can relate to rolify or any other component of your application.

That's basically what you ask. But, I would recommend not to take this way.

I've had a similar experience with a project I'm working on. I was trying to build an admin based add-user page and tried to use the devise registration pages as base and modify them.

However what I experienced was customizing these controllers and views (especially controllers) is getting cumbersome when you begin to change the actual dynamics of the page. You might find yourself digging deeper and deeper to ensure that whole authentication model runs without any problems.

Instead what I did was to introduce my own controller. Since devise exposes the authentication model and methods it's fairly easy to do standard task such as adding, removing and updating users. Your controllers will be very trivial, in fact with cancancan it might be enough to write a skeleton controller (with no method body) using load_and_authorize_resource that handles resource operations automatically.

You can replicate views of devise and use with this controller. This way you provide a similar frontend experience with devise.

Most important merit in this approach is you do not extend devise and leave it to work as a component. Thus, anything that will change in your project or in devise will not affect you much.

infiniteRefactor
  • 1,940
  • 15
  • 22