feat: add user deletion functionality

- Implement user destroy action in UsersController
- Add admin check for user deletion
- Update user view to include delete link for admins
- Add migration to add admin attribute to users
- Update tests to cover new admin functionality

This commit introduces the ability for admin users to delete
other users from the system. It includes necessary checks to
ensure that only admins can perform this action, along with
updates to the user interface and tests to validate the
new behavior.
This commit is contained in:
songtianlun 2025-01-05 18:27:13 +08:00
parent 022eae3029
commit f2c7d02eed
8 changed files with 69 additions and 7 deletions

View File

@ -1,7 +1,8 @@
class UsersController < ApplicationController
include SessionsHelper
before_action :logged_in_user, only: [ :index, :edit, :update ]
before_action :logged_in_user, only: [ :index, :edit, :update, :destroy ]
before_action :correct_user, only: [ :edit, :update ]
before_action :admin_user, only: [ :destroy ]
def index
# @users = User.all
@ -46,6 +47,12 @@ class UsersController < ApplicationController
end
end
def destroy
User.find(params[:id]).destroy
flash[:success] = "User deleted"
redirect_to users_url
end
private
def user_params
@ -65,4 +72,8 @@ class UsersController < ApplicationController
@user = User.find(params[:id])
redirect_to(root_url) unless current_user?(@user)
end
def admin_user
redirect_to(root_url) unless current_user.admin?
end
end

View File

@ -1,4 +1,11 @@
<li>
<%= gravatar_for user, size: 50 %>
<%= link_to user.name, user %>
<% if current_user.admin? && !current_user?(user) %>
| <%= link_to "delete", user,
data: {
turbo_method: :delete,
confirm: "You sure?"
} %>
<% end %>
</li>

View File

@ -0,0 +1,5 @@
class AddAdminToUsers < ActiveRecord::Migration[8.0]
def change
add_column :users, :admin, :boolean, default: false
end
end

3
db/schema.rb generated
View File

@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema[8.0].define(version: 2025_01_02_072521) do
ActiveRecord::Schema[8.0].define(version: 2025_01_05_095157) do
create_table "users", force: :cascade do |t|
t.string "name"
t.string "email"
@ -18,6 +18,7 @@ ActiveRecord::Schema[8.0].define(version: 2025_01_02_072521) do
t.datetime "updated_at", null: false
t.string "password_digest"
t.string "remember_digest"
t.boolean "admin", default: false
t.index ["email"], name: "index_users_on_email", unique: true
end
end

View File

@ -11,7 +11,8 @@
User.create!(name: "Example User",
email: "example@example.com",
password: "foobar",
password_confirmation: "foobar")
password_confirmation: "foobar",
admin: true)
99.times do |n|
name = Faker::Name.name

View File

@ -35,4 +35,30 @@ class UsersControllerTest < ActionDispatch::IntegrationTest
assert flash.empty?
assert_redirected_to root_url
end
test "should not allow the admin attribute to be edited via the web" do
log_in_as(@other_user)
assert_not @other_user.admin?
patch user_path(@other_user), params: {
user: { password: "password",
password_confirmation: "password",
admin: true }
}
assert_not @other_user.reload.admin?
end
test "should redirect destroy when not logged in" do
assert_no_difference "User.count" do
delete user_path(@user)
end
assert_redirected_to login_url
end
test "should redirect destroy when logged in as a non-admin" do
log_in_as(@other_user)
assert_no_difference "User.count" do
delete user_path(@user)
end
assert_redirected_to root_url
end
end

View File

@ -7,6 +7,7 @@ one:
michael:
name: Michael Example
email: michael@example.com
admin: true
password_digest: <%= User.digest('password') %>
archer:

View File

@ -2,16 +2,26 @@ require "test_helper"
class UsersIndexTest < ActionDispatch::IntegrationTest
def setup
@user = users(:michael)
@admin = users(:michael)
@non_admin = users(:archer)
end
test "index including pagination" do
log_in_as(@user)
test "index including pagination and delete links" do
log_in_as(@admin)
get users_path
assert_template "users/index"
assert_select "ul.pagination"
User.page(1).each do |user|
first_page_of_users = User.page(1)
first_page_of_users.each do |user|
assert_select "a[href=?]", user_path(user), text: user.name
unless user == @admin
assert_select "a[href=?]", user_path(user), text: "delete"
end
end
assert_difference "User.count", -1 do
delete user_path(@non_admin)
end
end
end