Search code examples
ruby-on-railsrubyruby-on-rails-4deviseadmin

Rails: Only allow admin user to create new users in Rails with Devise (No external modules)


Currently, my Users database has a column called "admin" with a boolean value and the default set to false. I have one admin user seeded into the database.

How do write my application so that users who are the admin can create new users, but users who are not cannot? (Also, users should be created only by the admin)

It seems like there should be a simple way to do this in devise that does not involve using some external module. So far however, I have not been able to find a satisfactory answer.

I would be more likely to mark the solution which is devise only. (One that is simply standard MVC/Rails solution a plus) However, if there really is a better way to do it that doesn't involve CanCan I may accept that too.

NOTE:

I have been searching around for a while and I've found several other stackoverflow questions that are very similar to this one, but either don't quite answer the question, or use other non-devise modules. (Or both)


Solution

  • To implement the authorization, use a method on the controller

    Exactly as suggested by @diego.greyrobot

    class UsersController < ApplicationController
      before_filter :authorize_admin, only: :create
    
      def create
        # admins only
      end
    
      private
    
      # This should probably be abstracted to ApplicationController
      # as shown by diego.greyrobot
      def authorize_admin
        return unless !current_user.admin?
        redirect_to root_path, alert: 'Admins only!'
      end
    end
    

    To sidestep the Devise 'already logged in' problem, define a new route for creating users.

    We will simply define a new route to handle the creation of users and then point the form to that location. This way, the form submission does not pass through the devise controller so you can feel free to use it anywhere you want in the normal Rails way.

    # routes.rb
    Rails.application.routes.draw do
    
      devise_for :users
      resources :users, except: :create
    
      # Name it however you want
      post 'create_user' => 'users#create', as: :create_user      
    
    end
    
    # users/new.html.erb
    # notice the url argument
    <%= form_for User.new, url: create_user_path do |f| %>
      # The form content
    <% end %>