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 'rolify'
|
||||||
|
|
||||||
|
gem 'cancancan'
|
||||||
|
|
||||||
gem 'webpacker'
|
gem 'webpacker'
|
||||||
|
|
||||||
gem 'kaminari'
|
gem 'kaminari'
|
||||||
|
|
|
@ -84,6 +84,7 @@ GEM
|
||||||
bootsnap (1.17.0)
|
bootsnap (1.17.0)
|
||||||
msgpack (~> 1.2)
|
msgpack (~> 1.2)
|
||||||
builder (3.2.4)
|
builder (3.2.4)
|
||||||
|
cancancan (3.5.0)
|
||||||
capybara (3.39.2)
|
capybara (3.39.2)
|
||||||
addressable
|
addressable
|
||||||
matrix
|
matrix
|
||||||
|
@ -291,6 +292,7 @@ PLATFORMS
|
||||||
|
|
||||||
DEPENDENCIES
|
DEPENDENCIES
|
||||||
bootsnap
|
bootsnap
|
||||||
|
cancancan
|
||||||
capybara
|
capybara
|
||||||
debug
|
debug
|
||||||
devise
|
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
|
class ApplicationController < ActionController::Base
|
||||||
before_action :authenticate_user!
|
before_action :authenticate_user!
|
||||||
end
|
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 :authenticate_user!
|
||||||
before_action :set_user, only: [:edit, :update, :destroy]
|
before_action :set_user, only: [:edit, :update, :destroy]
|
||||||
before_action :require_admin
|
before_action :require_admin
|
||||||
|
load_and_authorize_resource
|
||||||
|
|
||||||
def index
|
def index
|
||||||
@users = User.all
|
@users = User.all
|
||||||
|
@ -10,8 +11,20 @@ class UsersController < ApplicationController
|
||||||
def edit
|
def edit
|
||||||
end
|
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
|
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.'
|
redirect_to users_path, notice: 'User was successfully updated.'
|
||||||
else
|
else
|
||||||
render :edit
|
render :edit
|
||||||
|
@ -30,7 +43,7 @@ class UsersController < ApplicationController
|
||||||
end
|
end
|
||||||
|
|
||||||
def user_params
|
def user_params
|
||||||
params.require(:user).permit(:email, :admin)
|
params.require(:user).permit(:email, :password, :password_confirmation, roles: [])
|
||||||
end
|
end
|
||||||
|
|
||||||
def require_admin
|
def require_admin
|
||||||
|
@ -38,4 +51,25 @@ class UsersController < ApplicationController
|
||||||
redirect_to root_path, alert: 'Only admins are allowed to access this section.'
|
redirect_to root_path, alert: 'Only admins are allowed to access this section.'
|
||||||
end
|
end
|
||||||
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
|
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| %>
|
<%= form_with(model: user, local: true, html: { class: 'needs-validation', novalidate: true }) do |form| %>
|
||||||
|
<!-- Display errors, if any -->
|
||||||
<% if user.errors.any? %>
|
<% if user.errors.any? %>
|
||||||
<div id="error_explanation" class="alert alert-danger" role="alert">
|
<div id="error_explanation" class="alert alert-danger" role="alert">
|
||||||
<h4><%= pluralize(user.errors.count, "error") %> prohibited this user from being saved:</h4>
|
<h4><%= pluralize(user.errors.count, "error") %> prohibited this user from being saved:</h4>
|
||||||
|
@ -10,16 +11,19 @@
|
||||||
</div>
|
</div>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
||||||
|
<!-- Email field -->
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<%= form.label :email, class: 'form-label' %>
|
<%= form.label :email, class: 'form-label' %>
|
||||||
<%= form.email_field :email, id: :user_email, class: 'form-control' %>
|
<%= form.email_field :email, id: :user_email, class: 'form-control' %>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mb-3 form-check">
|
<!-- Role selection -->
|
||||||
<%= form.check_box :admin, class: 'form-check-input', id: :user_admin %>
|
<div class="mb-3">
|
||||||
<%= form.label :admin, class: 'form-check-label' %>
|
<%= 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>
|
</div>
|
||||||
|
|
||||||
|
<!-- Submit button -->
|
||||||
<div class="actions">
|
<div class="actions">
|
||||||
<%= form.submit 'Save', class: 'btn btn-dark' %>
|
<%= form.submit 'Save', class: 'btn btn-dark' %>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
<% @users.each do |user| %>
|
<% @users.each do |user| %>
|
||||||
<tr>
|
<tr>
|
||||||
<td><%= user.email %></td>
|
<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>
|
<td>
|
||||||
<%= link_to edit_user_path(user), class: 'btn btn-info btn-sm' do %>
|
<%= link_to edit_user_path(user), class: 'btn btn-info btn-sm' do %>
|
||||||
<i class="bi bi-pencil-fill" style="color: white;"></i>
|
<i class="bi bi-pencil-fill" style="color: white;"></i>
|
||||||
|
@ -31,9 +31,15 @@
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- Optionally, include action buttons or links here -->
|
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-12 d-flex justify-content-between mb-4">
|
<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 -->
|
<%= link_to 'Back to Home', root_path, class: "btn btn-secondary" %> <!-- Adjust as needed -->
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -84,6 +84,10 @@ Rails.application.routes.draw do
|
||||||
|
|
||||||
resources :forms
|
resources :forms
|
||||||
resources :users
|
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