Finished adding the ability for admins to create new users.
This commit is contained in:
parent
1d5646e61c
commit
867deebf20
2
Gemfile
2
Gemfile
|
@ -30,6 +30,8 @@ gem 'devise'
|
|||
|
||||
gem 'rolify'
|
||||
|
||||
gem 'cancancan'
|
||||
|
||||
gem 'webpacker'
|
||||
|
||||
gem 'kaminari'
|
||||
|
|
|
@ -84,6 +84,7 @@ GEM
|
|||
bootsnap (1.17.0)
|
||||
msgpack (~> 1.2)
|
||||
builder (3.2.4)
|
||||
cancancan (3.5.0)
|
||||
capybara (3.39.2)
|
||||
addressable
|
||||
matrix
|
||||
|
@ -291,6 +292,7 @@ PLATFORMS
|
|||
|
||||
DEPENDENCIES
|
||||
bootsnap
|
||||
cancancan
|
||||
capybara
|
||||
debug
|
||||
devise
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
class AdminController < ApplicationController
|
||||
before_action :authenticate_user!
|
||||
load_and_authorize_resource class: User
|
||||
|
||||
def new_user
|
||||
@user = User.new
|
||||
end
|
||||
|
||||
def create_user
|
||||
@user = User.new(user_params)
|
||||
if @user.save
|
||||
# Add role to the user here if needed e.g., user.add_role :new_role
|
||||
redirect_to admin_users_path, notice: 'User was successfully created.'
|
||||
else
|
||||
render :new_user
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def user_params
|
||||
params.require(:user).permit(:email, :password, :password_confirmation)
|
||||
# Add other fields as needed
|
||||
end
|
||||
end
|
||||
|
|
@ -1,3 +1,7 @@
|
|||
class ApplicationController < ActionController::Base
|
||||
before_action :authenticate_user!
|
||||
rescue_from CanCan::AccessDenied do |exception|
|
||||
redirect_to root_url, alert: "Access denied."
|
||||
end
|
||||
end
|
||||
|
|
@ -2,6 +2,7 @@ class UsersController < ApplicationController
|
|||
before_action :authenticate_user!
|
||||
before_action :set_user, only: [:edit, :update, :destroy]
|
||||
before_action :require_admin
|
||||
load_and_authorize_resource
|
||||
|
||||
def index
|
||||
@users = User.all
|
||||
|
@ -10,8 +11,20 @@ class UsersController < ApplicationController
|
|||
def edit
|
||||
end
|
||||
|
||||
def create
|
||||
@user = User.new(user_params)
|
||||
if @user.save
|
||||
assign_roles(@user)
|
||||
redirect_to users_path, notice: 'User was successfully created.'
|
||||
else
|
||||
render :new
|
||||
end
|
||||
end
|
||||
|
||||
def update
|
||||
if @user.update(user_params)
|
||||
# Assumes @user is already set from a before_action callback
|
||||
if @user.update(user_params.except(:roles))
|
||||
update_user_roles(@user, user_params[:roles])
|
||||
redirect_to users_path, notice: 'User was successfully updated.'
|
||||
else
|
||||
render :edit
|
||||
|
@ -30,7 +43,7 @@ class UsersController < ApplicationController
|
|||
end
|
||||
|
||||
def user_params
|
||||
params.require(:user).permit(:email, :admin)
|
||||
params.require(:user).permit(:email, :password, :password_confirmation, roles: [])
|
||||
end
|
||||
|
||||
def require_admin
|
||||
|
@ -38,4 +51,25 @@ class UsersController < ApplicationController
|
|||
redirect_to root_path, alert: 'Only admins are allowed to access this section.'
|
||||
end
|
||||
end
|
||||
|
||||
def assign_roles(user)
|
||||
user.roles.delete_all # Clear all roles before reassigning to prevent duplicates
|
||||
|
||||
# Assuming roles are passed as an array of role names from the form
|
||||
# and that the form sends an empty string if no roles are selected.
|
||||
selected_roles = params[:user][:roles].reject(&:blank?)
|
||||
|
||||
selected_roles.each do |role_name|
|
||||
user.add_role(role_name) unless user.has_role?(role_name)
|
||||
end
|
||||
end
|
||||
|
||||
def update_user_roles(user, roles_names)
|
||||
user.roles.delete_all # Remove existing roles
|
||||
roles_names.each do |role_name|
|
||||
user.add_role(role_name) unless role_name.blank?
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
module AdminHelper
|
||||
end
|
|
@ -0,0 +1,16 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class Ability
|
||||
include CanCan::Ability
|
||||
|
||||
def initialize(user)
|
||||
user ||= User.new # guest user (not logged in)
|
||||
if user.has_role? :admin
|
||||
can :manage, :all
|
||||
can :create, User if user.has_role? :admin
|
||||
else
|
||||
can :read, :all
|
||||
# Define other abilities for other roles
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,52 @@
|
|||
<div class="container mt-5">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-6">
|
||||
<h2 class="mb-3 text-center">Create New User</h2>
|
||||
|
||||
<%= form_for(@user, url: admin_users_path, html: { class: 'needs-validation', novalidate: true }) do |f| %>
|
||||
<div class="mb-3">
|
||||
<%= f.label :email, class: 'form-label' %>
|
||||
<%= f.email_field :email, class: 'form-control', placeholder: 'Enter email', required: true %>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<%= f.label :password, class: 'form-label' %>
|
||||
<%= f.password_field :password, class: 'form-control', placeholder: 'Password', required: true %>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<%= f.label :password_confirmation, "Confirm Password", class: 'form-label' %>
|
||||
<%= f.password_field :password_confirmation, class: 'form-control', placeholder: 'Confirm Password', required: true %>
|
||||
</div>
|
||||
|
||||
<div class="actions text-center">
|
||||
<%= f.submit "Create User", class: 'btn btn-dark' %>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<%# This is to indicate to the User if the passwords didn't match %>
|
||||
<script>
|
||||
document.addEventListener("DOMContentLoaded", function() {
|
||||
const password = document.querySelector('#user_password');
|
||||
const confirmPassword = document.querySelector('#user_password_confirmation');
|
||||
const messageContainer = document.createElement('div');
|
||||
messageContainer.style.color = 'red';
|
||||
|
||||
// Append the messageContainer below the confirmPassword field
|
||||
confirmPassword.parentNode.insertBefore(messageContainer, confirmPassword.nextSibling);
|
||||
|
||||
function validatePassword(){
|
||||
if(password.value !== confirmPassword.value) {
|
||||
messageContainer.textContent = "Passwords need to match!";
|
||||
} else {
|
||||
messageContainer.textContent = "";
|
||||
}
|
||||
}
|
||||
|
||||
password.onchange = validatePassword;
|
||||
confirmPassword.onkeyup = validatePassword;
|
||||
});
|
||||
</script>
|
|
@ -1,4 +1,5 @@
|
|||
<%= form_with(model: user, local: true, html: { class: 'needs-validation', novalidate: true }) do |form| %>
|
||||
<!-- Display errors, if any -->
|
||||
<% if user.errors.any? %>
|
||||
<div id="error_explanation" class="alert alert-danger" role="alert">
|
||||
<h4><%= pluralize(user.errors.count, "error") %> prohibited this user from being saved:</h4>
|
||||
|
@ -10,16 +11,19 @@
|
|||
</div>
|
||||
<% end %>
|
||||
|
||||
<!-- Email field -->
|
||||
<div class="mb-3">
|
||||
<%= form.label :email, class: 'form-label' %>
|
||||
<%= form.email_field :email, id: :user_email, class: 'form-control' %>
|
||||
</div>
|
||||
|
||||
<div class="mb-3 form-check">
|
||||
<%= form.check_box :admin, class: 'form-check-input', id: :user_admin %>
|
||||
<%= form.label :admin, class: 'form-check-label' %>
|
||||
<!-- Role selection -->
|
||||
<div class="mb-3">
|
||||
<%= form.label :roles, 'Assign Role', class: 'form-label' %>
|
||||
<%= form.select :roles, options_for_select(Role.pluck(:name), user.roles.pluck(:name)), {}, { multiple: true, class: 'form-control' } %>
|
||||
</div>
|
||||
|
||||
<!-- Submit button -->
|
||||
<div class="actions">
|
||||
<%= form.submit 'Save', class: 'btn btn-dark' %>
|
||||
</div>
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
<% @users.each do |user| %>
|
||||
<tr>
|
||||
<td><%= user.email %></td>
|
||||
<td><%= user.admin? ? 'Yes' : 'No' %></td>
|
||||
<td><%= user.has_role?(:admin) ? 'Yes' : 'No' %></td> <!-- Assuming you're using Rolify for role management -->
|
||||
<td>
|
||||
<%= link_to edit_user_path(user), class: 'btn btn-info btn-sm' do %>
|
||||
<i class="bi bi-pencil-fill" style="color: white;"></i>
|
||||
|
@ -31,9 +31,15 @@
|
|||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Optionally, include action buttons or links here -->
|
||||
|
||||
|
||||
<div class="row">
|
||||
<div class="col-12 d-flex justify-content-between mb-4">
|
||||
<!-- Button for Admins to add a new user -->
|
||||
<% if can?(:create, User) %> <!-- Checks if the current user has the permission to create new users -->
|
||||
<%= link_to 'Add New User', new_admin_user_path, class: "btn btn-dark" %>
|
||||
<% end %>
|
||||
|
||||
<%= link_to 'Back to Home', root_path, class: "btn btn-secondary" %> <!-- Adjust as needed -->
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -85,6 +85,10 @@ Rails.application.routes.draw do
|
|||
resources :forms
|
||||
resources :users
|
||||
|
||||
# Custom route for admin to create a new user
|
||||
get 'admin/users/new', to: 'admin#new_user', as: :new_admin_user
|
||||
post 'admin/users', to: 'admin#create_user', as: :admin_users
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
require "test_helper"
|
||||
|
||||
class AdminControllerTest < ActionDispatch::IntegrationTest
|
||||
# test "the truth" do
|
||||
# assert true
|
||||
# end
|
||||
end
|
Loading…
Reference in New Issue