From f2c7d02eed11b9afe54097bd32dd194b476c0575 Mon Sep 17 00:00:00 2001 From: songtianlun Date: Sun, 5 Jan 2025 18:27:13 +0800 Subject: [PATCH] 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. --- app/controllers/users_controller.rb | 13 +++++++++- app/views/users/_user.html.erb | 7 +++++ .../20250105095157_add_admin_to_users.rb | 5 ++++ db/schema.rb | 3 ++- db/seeds.rb | 3 ++- test/controllers/users_controller_test.rb | 26 +++++++++++++++++++ test/fixtures/users.yml | 1 + test/integration/users_index_test.rb | 18 ++++++++++--- 8 files changed, 69 insertions(+), 7 deletions(-) create mode 100644 db/migrate/20250105095157_add_admin_to_users.rb diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index 0b54b14..cb9b88d 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -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 diff --git a/app/views/users/_user.html.erb b/app/views/users/_user.html.erb index d54c0e3..be73320 100644 --- a/app/views/users/_user.html.erb +++ b/app/views/users/_user.html.erb @@ -1,4 +1,11 @@
  • <%= 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 %>
  • \ No newline at end of file diff --git a/db/migrate/20250105095157_add_admin_to_users.rb b/db/migrate/20250105095157_add_admin_to_users.rb new file mode 100644 index 0000000..c1f08cf --- /dev/null +++ b/db/migrate/20250105095157_add_admin_to_users.rb @@ -0,0 +1,5 @@ +class AddAdminToUsers < ActiveRecord::Migration[8.0] + def change + add_column :users, :admin, :boolean, default: false + end +end diff --git a/db/schema.rb b/db/schema.rb index ee50448..93b2f85 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -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 diff --git a/db/seeds.rb b/db/seeds.rb index 155583d..4c18990 100644 --- a/db/seeds.rb +++ b/db/seeds.rb @@ -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 diff --git a/test/controllers/users_controller_test.rb b/test/controllers/users_controller_test.rb index 9aca241..14fba91 100644 --- a/test/controllers/users_controller_test.rb +++ b/test/controllers/users_controller_test.rb @@ -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 diff --git a/test/fixtures/users.yml b/test/fixtures/users.yml index 2f60abe..7944493 100644 --- a/test/fixtures/users.yml +++ b/test/fixtures/users.yml @@ -7,6 +7,7 @@ one: michael: name: Michael Example email: michael@example.com + admin: true password_digest: <%= User.digest('password') %> archer: diff --git a/test/integration/users_index_test.rb b/test/integration/users_index_test.rb index a2064d1..5b11830 100644 --- a/test/integration/users_index_test.rb +++ b/test/integration/users_index_test.rb @@ -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