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

0112 picture 0112 · Jul 21, 2014 · Viewed 17.9k times · Source

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)

Answer

Adam Waselnuk picture Adam Waselnuk · Oct 17, 2014

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 %>