Eric Norcross
Eric Norcross

Reputation: 4306

Allowing admins to add users with Devise

I'm trying to make it so only admins can add uses with devise. I've gotten it mostly working however now when I'm logged in as an admin and submit the sign up form it kicks me back with the error: You are already signed in.

I've tried to follow the instructions here: http://wiki.summercode.com/rails_authentication_with_devise_and_cancan but it doesn't seem to mention this situation.

Do I need to do further overriding in the editors_controller to allow this?

Here are my routes ("editors" is the name of my user model):

devise_for :admins, :skip => [:registrations]

as :admin do
  get 'admin/editors'        => 'editors#index',                  as: :admin_editors
  get 'admin/editors/new'    => 'editors#new',                    as: :new_editor
  delete 'admin/editors/:id' => 'editors#destroy',                as: :destroy_editor
end


devise_for :editors, :skip => [:registrations],  :controllers => { :registrations => "editors" }

and my editors_controller in "app/controllers/"

    class EditorsController < Devise::RegistrationsController
  before_filter :check_permissions, :only => [:new, :create, :cancel]
  skip_before_filter :require_no_authentication

  def dashboard
    render "editors/dashboard.html.haml"
  end

  def index
    @editors = Editor.all
    respond_to do |format|
      format.html
    end
  end

  private
    def check_permissions
      authorize! :create, resource
    end
end

EDIT I noticed this Processing by Devise::RegistrationsController#create as HTML in the logs when I submit the form. I had suspected that perhaps the skip_before_filter :require_no_authentication wasn't being called, but assumed that because the EditorsController was inheriting from RegistrationController that before filter would work properly. Is that not the case?

Upvotes: 8

Views: 9661

Answers (3)

guero64
guero64

Reputation: 1049

Using Rails 4.2.6 here (my model is User instead of Editor). The following solution bypasses (I think) any devise actions that may interfere with new User creation by the admin:

Add this action to the Users controller:

def savenew
  User.create_new_user(user_params)
  redirect_to action: 'index'
end

Add this private method to the Users controller if it does not exist:

private

def user_params
  params.require(:user).permit(:email, :password,      
                               :password_confirmation)
end

Add this to config/routes.rb:

match '/savenew', to: 'users#savenew', via: :post

Add this class method to the User model:

def self.create_new_user(params)
  @user = User.create!(params)
end

I don't have a separate Admin class in my application. Instead, I defined an admin attribute for Users and check for it with a :validate_admin before_action filter in the UsersController.

I wanted to be able to create a new user from the :index view, so I added a button:

<%= button_to 'New User', '/new_user', class: 'btn btn-primary',
                          method: :get %>

You might have to tweak the above solution if you have any after_create actions in the User model (e.g. sending a welcome email).

Upvotes: 0

Richard Grossman
Richard Grossman

Reputation: 731

None of the googleable solutions worked when I tried them. This works

What I did was create a new action in the controller and a new route for it, and connect the links on my views that normally connect to create to now call my route and action.

But that wasn't enough. Because Devise is listening and will grab any add you try to do and validate it through it's own code. So instead I just add the new user record with a sql insert.

Add this route

post 'savenew', to: 'users#savenew'

Add this action to the user controller:

def savenew
  rawsql = "insert into users (email, created_at,updated_at) values ('#{user_params[:email]}',now(), now())"
  sql = rawsql
  ActiveRecord::Base.connection.execute(sql)
  redirect_to action: 'index''
end

View: new.html.erb change the form_for so that submit will go to the new route and action, not the default Rails one.

<%= form_for User, :url => {:action => "savenew"} do |f| %>

Upvotes: 1

Jeremy Green
Jeremy Green

Reputation: 8574

You'll want to implement your own create method on EditorsController instead of inheriting that action from Devise::RegistrationsController. As you're seeing, the method in Devise::RegistrationsController will first check to see if you're already logged in and kick you back if you are. If you're not logged in it will create a User account and then log you in as that user.

You're trying to get around that problem with skip_before_filter :require_no_authentication, but it's likely that your form is POSTing to /editors instead of /admin/editors. So, you'll need to add a route that allows you to get to create on the EditorsController :

as :admin do
  post 'admin/editors' => 'editors#create'
  # your other :admin routes here
end

Then you'd want to implement a scaled down version of create. You probably want something kind of like this :

class EditorsController < Devise::RegistrationsController
  def create
    build_resource(sign_up_params)
    if resource.save
      redirect_to admin_editors_path
    else
      clean_up_passwords resource
      respond_with resource
    end
  end

  # your other methods here
end

You'll also want to make sure that the admin/editors/new template is pointing the form to the correct route ('admin/editors').

Upvotes: 6

Related Questions