Railsチュートリアル 第10章 ユーザーの更新・表示・削除 - ユーザーを削除する

# 何をするか

* ユーザー削除が可能な権限を持つ管理ユーザーのクラスの実装
* ユーザーを削除するためのリンクの追加
* RDBからユーザーを削除する動作の実装

ここまでの実装が完了すれば、Userリソースに対し、RESTが求めるすべての動作の実装が完了することになります。

Railsチュートリアル本文においては、ユーザーを削除するためのリンクを追加したサイトレイアウトのモックアップは、[図 10.13](https://railstutorial.jp/chapters/updating_and_deleting_users?version=5.1#fig-user_index_delete_links_mockup)に示されています。

# 管理ユーザー

Userモデルに、boolean型の値を取る`admin`という属性を追加します。特権を持つ管理ユーザーを識別するために用いる属性です。

![User_full.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/323778/86b8ec69-64fe-4d37-c2f3-92776991bb84.png)

boolean型の`admin`属性をUserモデルに追加すると、Railsによって、Userモデルの`admin?`というメソッドが自動で追加されます。

## マイグレーションの生成と修正

続いて、マイグレーションを生成します。

```
# rails generate migration add_admin_to_users admin:boolean
Running via Spring preloader in process 12240
      invoke  active_record
      create    db/migrate/[timestamp]_add_admin_to_users.rb
```

`db/migrate/[timestamp]_add_admin_to_users.rb`というマイグレーションが生成されました。ただ、生成されたマイグレーションに若干の修正を加える必要があります。

```diff:db/migrate/[timestamp]_add_admin_to_users.rb
  class AddAdminToUsers < ActiveRecord::Migration[5.1]
    def change
-     add_column :users, :admin, :boolean
+     add_column :users, :admin, :boolean, default: false
    end
  end
```

`default: false`という引数を与えています。「デフォルトでは管理権限はない」ということを明示するためです。

後はマイグレーションを実行すれば、Userモデルに`admin`属性が実装され、`admin?`メソッドも使えるようになります。

```
# rails db:migrate
== [timestamp] AddAdminToUsers: migrating ==================================
-- add_column(:users, :admin, :boolean)
   -> 0.0152s
== [timestamp] AddAdminToUsers: migrated (0.0186s) =========================
```

## `admin?`メソッドを試してみる

```
# rails console --sandbox

>> user = User.first
  User Load (4.6ms)  SELECT  "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT ?  [["LIMIT", 1]]
=> #<User id: 1, ..., admin: nil>
>> user.admin?
=> false
>> user.toggle!(:admin)
   (0.2ms)  SAVEPOINT active_record_1
  SQL (37.0ms)  UPDATE "users" SET "updated_at" = ?, "admin" = ? WHERE "users"."id" = ?  [["updated_at", "2019-11-28 21:42:04.018070"], ["admin", "t"], ["id", 1]]
   (0.1ms)  RELEASE SAVEPOINT active_record_1
=> true
>> user.admin
=> true
```

ここでは、`toggle!`メソッドを使って、id=1のユーザーの`admin`属性値を`false`から`true`に反転しています。`follow_redirect!`や`find_by!`等の`!`とは異なり、この場合の`!`は「破壊的代入」という意味ですね。

## id=1のユーザーのみ、デフォルトで管理者とする

まず、`db/seeds.rb`の内容を変更し、id=1のユーザーをデフォルトで管理者とするようにサンプルデータ生成タスクの内容を変更します。

```diff:db/seeds.rb
  User.create(name:                  "Example User",
              email:                 "example@railstutorial.org",
              password:              "foobar",
-             password_confirmation: "foobar")
+             password_confirmation: "foobar",
+             admin: true)

  99.times do |n|
    name = Faker::Name.name
    email = "example-#{n+1}@railstutorial.org"
    password = "password"
    User.create!( name:                  name,
                  email:                 email,
                  password:              password,
                  password_confirmation: password)
  end
```

次に、データベースをリセットし、サンプルデータを再生成します。

```
# rails db:migrate:reset
Dropped database 'db/development.sqlite3'
Dropped database 'db/test.sqlite3'
Created database 'db/development.sqlite3'
Created database 'db/test.sqlite3'
...略

# rails db:seed
```

`rails db:seed`は、正常に完了した場合、シェルには何も表示されません。

なお、私はここで少々つまづきました。顛末は[db/seeds.rbの中身を変更したらrails db:seedできない。そんなときにありがちな原因](https://qiita.com/rapidliner00/items/0e46d1e3d2c18c5b6b63)に記述ています。

## Strong Parametersにより、`admin`属性を保護する

特に対策をしていない場合、例えば以下のような`PATCH`リクエストにより、任意のユーザーの`admin`属性の値を変更することができてしまいます。

```
patch /users/17?admin=1
```

UNIX系OSのroot権限もそうですが、「任意のユーザーが、任意の属性を変更可能である」というのは非常に危険な状態です。なんとしても「一般ユーザーが編集できてはいけない属性を編集できないようにする」という仕組みを実装する必要があります。

4.0以降のRailsにおいては、「一般ユーザーが編集できてはいけない属性を編集できないようにする」という要求を実現する仕組みとして、Strong Parametersという機能が実装されています。Railsチュートリアル本文では、[節7.3.2](https://railstutorial.jp/chapters/sign-up?version=4.0#sec-strong_parameters)で言及されていました。

Railsチュートリアルをここまで順番通りに進めていれば、「Strong Parametersによって`admin`属性を保護する」という仕組みは、サンプルアプリケーションにすでに実装されているはずです。コードは以下です。

```ruby:app/controllers/users_controller.rb
class UsersController < ApplicationController
  # ...略
  private

    def user_params
      params.require(:user).permit(:name, :email, :password, :password_confirmation)
    end
    # ...略
end
```

`user_params`メソッド内の`params.require(:user).permit`の引数に`:admin`が含まれていないことがポイントです。この実装により、「任意のユーザーが自分に管理者権限を与えること」は防止されています。

# 演習 - 管理ユーザー

## 1.1. Web経由でadmin属性を変更できないことを確認するテストを実装するために、まずはadminをuser_paramsメソッド内の許可されたパラメータ一覧に追加するところから始めてみましょう。

```diff:app/controllers/users_controller.rb
  class UsersController < ApplicationController
    ...略

    private

      def user_params
-       params.require(:user).permit(:name, :email, :password, :password_confirmation)
+       params.require(:user).permit(:name, :email, :password, :password_confirmation, :admin)
      end
      ...略
  end
```

## 1.2. Web経由でadmin属性を変更できないことを確認してみましょう。

> 具体的には、リスト 10.56に示したように、`PATCH`を直接ユーザーのURL (/users/:id) に送信するテストを作成してみてください。

以下のようなテストを`test/controllers/users_controller_test.rb`に追加します。

```ruby:
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
```

ポイントは以下です。

* 以下の値は、`@other_user.password`とすると`update`が正常に完了しない
    * `params[:user][:password]`
    * `params[:user][:password_confirmation]`
* `reload`により、RDBに保存された`@other_user`を再度読み込む必要がある

特に`params[:user][:password]`および`params[:user][:password_confirmation]`の値については、1時間くらい悩んでしまいました。

このようなときに決め手となるのはやはり`debugger`ですね。

```diff:app/controllers/users_controller.rb#update
  def update
+   debugger
    if @user.update_attributes(user_params)
      flash[:success] = "Profile updated"
      redirect_to @user
    else
      render 'edit'
    end
  end
```

```
(byebug) user_params
<ActionController::Parameters {"password"=>nil, "password_confirmation"=>nil, "admin"=>"true"} permitted: true>
```

```
"password"=>nil, "password_confirmation"=>nil
```

ここを見てようやく気づきました。`params[:user][:password]`と`params[:user][:password_confirmation]`には、生文字列を与えなければダメなのだと…。

> テストが正しい振る舞いをしているかどうか確信を得るために、最初のテストの結果は`red`になるはずです。

```
# rails test test/controllers/users_controller_test.rb:35
Running via Spring preloader in process 12914
Started with run options --seed 32377

 FAIL["test_should_not_allow_the_admin_attribute_to_be_edited_via_the_web", UsersControllerTest, 0.8165606999828015]
 test_should_not_allow_the_admin_attribute_to_be_edited_via_the_web#UsersControllerTest (0.82s)
        Expected true to be nil or false
        test/controllers/users_controller_test.rb:41:in `block in <class:UsersControllerTest>'

  7/7: [===================================] 100% Time: 00:00:00, Time: 00:00:00

Finished in 0.82068s
1 tests, 2 assertions, 1 failures, 0 errors, 0 skips
```

悩み悩んだ挙げ句、ようやくテストが失敗してくれました。

```ruby:test/controllers/users_controller_test.rb（41行目）
assert_not @other_user.reload.admin?
```

現在の私の環境では、`test/controllers/users_controller_test.rb`の41行目は上記コードです。というわけで、テスト失敗時のメッセージの内容も、`:admin`属性の値が`true`になっていますという内容です。ここまで長かった。

### `user_params`の内容を本来の実装に戻して、もう一度テスト

```diff:app/controllers/users_controller.rb
  class UsersController < ApplicationController
    ...略

    private

      def user_params
-       params.require(:user).permit(:name, :email, :password, :password_confirmation, :admin)
+       params.require(:user).permit(:name, :email, :password, :password_confirmation)
      end

      ...略
  end
```

```
# rails test test/controllers/users_controller_test.rb:35
Running via Spring preloader in process 12927
Started with run options --seed 30515

  7/7: [===================================] 100% Time: 00:00:00, Time: 00:00:00

Finished in 0.82063s
1 tests, 2 assertions, 0 failures, 0 errors, 0 skips
```

今度はテストが成功しました。

# `destroy`アクション

## indexビュー用のuserパーシャルに、ユーザー削除用のリンクを追加する

続いて編集するのは、indexビュー用のuserパーシャルです。追加するのはユーザー削除用のリンクで、「管理者のみに表示される」という要件を満たす必要があります。

### ユーザー削除用のリンクの実体

```ruby:
<% if current_user.admin? && !current_user?(user) %>
  | <%= link_to "delete", user, method: :delete, data: { confirm: "You sure?" } %>
<% end %>
```

重要と思われるポイントは以下です。

* if文について
    * 「管理者のみに表示される」という要件を満たすために、`current_user.admin?`という記述がなされている
    * `!current_user?(user)`というのは、「現在ログイン中のユーザーが自分自身を削除することはできない」ことを意味する
* `DELETE`リクエストを発行するリンクの生成は、`link_to`の引数に`method: :delete`という記述があることがポイントとなる
* 確認メッセージを表示するようにしている

2019年現在のHTMLの仕様では、HTMLのフォームは直接`DELETE`（あるいは`PATCH`や`PUT`）リクエストを発行することはできません。そのため、Railsその他Webフレームワークでは、フレームワーク内部で実装された何らかの仕組みによって`DELETE`リクエストを発行するようにしています。

### 実際にindexビュー用のuserパーシャルの内容を変更する

`app/views/users/_user.html.erb`に、以下の変更を加えていきます。

```diff:app/views/users/_user.html.erb
  <li>
    <%= gravatar_for user, size: 50 %>
    <%= link_to user.name, user %>
+   <% if current_user.admin? && !current_user?(user) %>
+     | <%= link_to "delete", user, method: :delete, data: { confirm: "You sure?" } %>
+   <% end %>
  </li>
```

### （管理ユーザーでログインしている場合）deleteリンクがindexに表示されるようになる

<img width="1176" alt="スクリーンショット 2019-11-30 19.52.43.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/323778/a2ece094-ede8-4b58-0d1f-5531ba11f420.png">

ここまで実装が完了すれば、（管理ユーザーでログインしている場合に）deleteリンクがindexに表示されるようになるようになります。

## `destroy`アクションの実装

deleteリンクをクリックして実際にRDBからユーザーが削除されるようにするためには、Usersコントローラーに`destroy`アクションを実装する必要があります。

`destroy`アクションの実装内容は以下のとおりになります。

```ruby:UsersController#destroy
def destroy
  User.find(params[:id]).destroy
  flash[:success] = "User deleted"
  redirect_to users_url
end
```

`User.find.destroy`というメソッドチェーンが「RDBからユーザーを削除する」という動作の実体ですね。以降、「フラッシュメッセージの定義」からの「indexページへのリダイレクト」へと続きます。

### `destroy`アクションをbeforeフィルターの対象にする

`destroy`アクションも、`edit`や`update`と同様に「ログインユーザーのみが実行できる」ようにする必要があります。コードは以下です。

#### ログインユーザーでなければ`destroy`アクションを実行できない

```ruby:
before_action :logged_in_user, only: [:index, :edit, :update, :destroy]
```

#### 管理ユーザーでなければ`destroy`アクションを実行できない

さらに、「`destroy`アクションは管理ユーザーのみが実行できる」という保護も必要となります。「cURLなどのツールを使って、直接`DELETE`リクエストを対象リソースに送りつける」という想定外のアクセスを防ぐ必要があるためです。コードは以下です。

```ruby:
before_action :admin_user, only: :destroy
```

`:admin_user`を第一引数とする`before_action`において、`:only`をキーとするハッシュに与えているのは配列ではありません。`:destroy`というシンボルを直接与えています。この点は、`:logged_in_user`や`:correct_user`を第一引数とする`before_action`とは異なっています。

##### `admin_user`メソッドそのものの定義

`admin_user`メソッドそのものの定義は以下です。

```ruby:
def admin_user
  redirect_to(root_url) unless current_user.admin?
end
```

「管理ユーザーでなければ / にリダイレクトされる」という動作になります。

### 以上の実装を`app/controllers/users_controller.rb`に反映する

`app/controllers/users_controller.rb`全体の変更内容は以下のとおりです。

```diff:app/controllers/users_controller.rb
  class UsersController < ApplicationController
-   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 destroy
+     User.find(params[:id]).destroy
+     flash[:success] = "User deleted"
+     redirect_to users_url
+   end

    private

      ...略
+
+     # 管理者かどうか確認
+     def admin_user
+       redirect_to(root_url) unless current_user.admin?
+     end
  end
```

# 演習 - `destroy`アクション

## 1. 管理者ユーザーとしてログインし、試しにサンプルユーザを２〜３人削除してみましょう。ユーザーを削除すると、Railsサーバーのログにはどのような情報が表示されるでしょうか? 

```
Started DELETE "/users/100" ...略
Processing by UsersController#destroy as HTML
  Parameters: {"authenticity_token"=>"rhQj0KvhGPwbu2uDnnux9jBIBpt6RC00ly1hoqSWPiE3EHv2wyrDvy003EsFWoANTfm79aAsGcTQbHQUpIO9ng==", "id"=>"100"}
  User Load (2.5ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 1], ["LIMIT", 1]]
  User Load (2.5ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 100], ["LIMIT", 1]]
   (1.2ms)  begin transaction
  SQL (11.4ms)  DELETE FROM "users" WHERE "users"."id" = ?  [["id", 100]]
   (8.3ms)  commit transaction
Redirected to http://localhost:8080/users
Completed 302 Found in 119ms (ActiveRecord: 39.5ms)


Started GET "/users" ...略
Processing by UsersController#index as HTML
  User Load (2.4ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 1], ["LIMIT", 1]]
  Rendering users/index.html.erb within layouts/application
   (2.5ms)  SELECT COUNT(*) FROM "users"
  User Load (2.3ms)  SELECT  "users".* FROM "users" LIMIT ? OFFSET ?  [["LIMIT", 30], ["OFFSET", 0]]
  ...略
Completed 200 OK in 370ms (Views: 342.7ms | ActiveRecord: 7.2ms)
```

* /users/100 への`DELETE`リクエストに対して
    * `id`が100であるユーザーを対象として、SQLの`DELETE`文が発行されている
    * 最終的には /users へのリダイレクトで`DELETE`リクエストが完了している
* `/users`への`GET`リクエストに対して
    * 特に変わった動作はない

## フラッシュメッセージの内容

```diff:UsersController#destroy
  def destroy
    User.find(params[:id]).destroy
    flash[:success] = "User deleted"
+   debugger
    redirect_to users_url
  end
```

以上のようにして、`flash[:success]`の内容を確認してみましょう。

```
(byebug) flash[:success]
"User deleted"
```

フラッシュメッセージの内容にも問題ないようですね。

# ユーザー削除のテスト

## fixture内で最初に登場するユーザーを管理ユーザーとする

ユーザー削除、すなわち`destroy`アクションの動作をテストするためには、fixtureにも管理ユーザーが必要となります。最初に出てくるユーザー、ここでは`:rhakurei`さんを管理ユーザーとしましょう。

```
  rhakurei:
    name: Reimu Hakurei
    email: rhakurei@example.com
    password_digest: <%= User.digest('password') %>
+   admin: true

  mkirisame:
    name: Marisa Kirisame
    email: example.example@example.org
    password_digest: <%= User.digest('password') %>

  skomeiji:
    name: Satori Komeiji
    email: example_example@example.net
    password_digest: <%= User.digest('password') %>

  rusami:
    name: Renko Usami
    email: example0@example.com
    password_digest: <%= User.digest('password') %>

  <% 30.times do |n| %>
  user_<%= n %>:
    name:  <%= "User #{n}" %>
    email: <%= "user-#{n}@example.com" %>
    password_digest: <%= User.digest('password') %>
  <% end %>
```

## 管理ユーザーでないユーザーが`destroy`アクションを実行しようとした場合に対するテスト

表題のような操作は、Usersコントローラーによって拒否されます。そのため、テストの実装箇所は`test/controllers/users_controller_test.rb`となります。

### 非ログインユーザーが`destroy`アクションを実行しようとした場合に対するテスト

```ruby:
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
```

テストの内容は以下となります。

* `@user`に対して`DELETE`リクエストを発行し、前後でユーザー数が変わっていなければOK
* `@user`に対して`DELETE`リクエストを発行した後に、 /login にリダイレクトされればOK

### ログイン済みの非管理ユーザーが`destroy`アクションを実行しようとした場合に対するテスト

```ruby:
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
```

こちらのテストの内容は以下となります。

* `@user`に対して`DELETE`リクエストを発行し、前後でユーザー数が変わっていなければOK
* `@user`に対して`DELETE`リクエストを発行した後に、 / にリダイレクトされればOK

### ここまでのテストを実装する

上記の記述を踏まえ、`test/controllers/users_controller_test.rb`に実際のテスト内容を実装していきます。

```diff:test/controllers/users_controller_test.rb
  require 'test_helper'

  class UsersControllerTest < ActionDispatch::IntegrationTest

    def setup
      @user       = users(:rhakurei)
      @other_user = users(:mkirisame)
    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
```

実装内容に問題がなければ、この時点でテストは成功するはずです。

```
# rails test test/controllers/users_controller_test.rb
Running via Spring preloader in process 13026
Started with run options --seed 37178

  9/9: [===================================] 100% Time: 00:00:02, Time: 00:00:02

Finished in 2.68050s
9 tests, 18 assertions, 0 failures, 0 errors, 0 skips
```

## 管理ユーザーが`destroy`アクションを実行する場合に対するテスト、および、indexビューにおける"delete"リンクの表示に関するテスト

表題のパターンでは`destroy`アクションが成功します。そのため、テストによる影響範囲は、「Usersコントローラーの動作」のみならず、「Userモデルの内容」にまで及びます。コントローラーとモデルの双方に影響範囲が及ぶテストなので、実装箇所は統合テストとなります。今回は「/index 上のリンクから`destroy`アクションを呼び出す」という動作に対するテストなので、より詳細な実装箇所は`test/integration/users_index_test.rb`です。

また、`test/integration/users_index_test.rb`に実装するテストには、「indexビューに削除リンクが表示されるか否か」というテストも含まれます。「管理ユーザーであれば、indexビューで、自身以外の各ユーザーの削除リンクが表示される。管理ユーザーでなければ、indexビューに削除リンクは表示されない。」というのが正しい実装となります。

### 管理ユーザーに対する統合テスト

以下の動作に対するテストが必要となります。

* 一覧内の、自身以外のユーザーに対して削除リンクが表示される
* `@non_admin`というユーザーに対して`DELETE`リクエストが送信された場合、実際にRDBから当該ユーザーが削除される

対応するテストのコードは以下となります。

```ruby:
test "index as admin including pagination and delete links" do
  log_in_as(@admin)
  get users_path
  assert_template 'users/index'
  assert_select 'div.pagination'
  first_page_of_users = User.paginate(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
```

なお、このテストには、「indexビューに実装された、ページネーション機能に対するテスト」も含まれます。個人的には、「一つのテストコードで多くの機能に対するテストを詰め込みすぎではないか」という気はします。

### 非管理ユーザーのindexビューに対するテスト

非管理ユーザーのindexビューに対しては、以下の動作に対するテストが必要となります。

* 一覧内に削除リンクが表示されない

対応するテストのコードは以下になります。

```ruby:
test "index as non-admin" do
  log_in_as(@non_admin)
  get users_path
  assert_select 'a', text: 'delete', count: 0
end
```

個人的には、テストの粒度はこれくらいが丁度いい気がします。

### `test/integration/users_index_test.rb`の内容

差分ではなく、`test/integration/users_index_test.rb`全体を丸ごと書き換えてしまいます。コードは以下のとおりです。

```ruby:`test/integration/users_index_test.rb`
require 'test_helper'

class UsersIndexTest < ActionDispatch::IntegrationTest
  def setup
    @admin = users(:rhakurei)
    @non_admin = users(:mkirisame)
  end

  test "index as admin including pagination and delete links" do
    log_in_as(@admin)
    get users_path
    assert_template 'users/index'
    assert_select 'div.pagination'
    first_page_of_users = User.paginate(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

  test "index as non-admin" do
    log_in_as(@non_admin)
    get users_path
    assert_select 'a', text: 'delete', count: 0
  end
end
```

### この時点でテストは成功する

`test/integration/users_index_test.rb`に対してテストを実行してみましょう。

```
# rails test test/integration/users_index_test.rb
Running via Spring preloader in process 13117
Started with run options --seed 23568

  2/2: [===================================] 100% Time: 00:00:02, Time: 00:00:02

Finished in 2.94128s
2 tests, 63 assertions, 0 failures, 0 errors, 0 skips
```

ここまでの実装内容に問題がなければ、テストは成功するはずです。

# 演習 - ユーザー削除のテスト

## 1. 試しに[リスト 10.59](https://railstutorial.jp/chapters/updating_and_deleting_users?version=5.1#code-admin_destroy_before_filter)にある管理者ユーザーのbeforeフィルターをコメントアウトしてみて、テストの結果が`red`に変わることを確認してみましょう。

```diff:app/controllers/users_controller.rb
  class UsersController < ApplicationController
    before_action :logged_in_user, only: [:index, :edit, :update, :destroy]
    before_action :correct_user,   only: [:edit, :update]
-   before_action :admin_user,     only: :destroy
+   # before_action :admin_user,     only: :destroy

    ...略
  end
```

```
# rails test
Running via Spring preloader in process 13156
Started with run options --seed 29997

 FAIL["test_should_redirect_destroy_when_logged_in_as_a_non-admin", UsersControllerTest, 3.8563491000095382]
 test_should_redirect_destroy_when_logged_in_as_a_non-admin#UsersControllerTest (3.86s)
        "User.count" didn't change by 0.
        Expected: 34
          Actual: 33
        test/controllers/users_controller_test.rb:68:in `block in <class:UsersControllerTest>'

  43/43: [=================================] 100% Time: 00:00:04, Time: 00:00:04

Finished in 4.65755s
43 tests, 182 assertions, 1 failures, 0 errors, 0 skips
```

テストは確かに失敗します。`test/controllers/users_controller_test.rb`の「should redirect destroy when logged in as a non-admin」というテストで失敗しているようですね。当該テストのコードは以下です。

```ruby:
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
```

当該テストの要求は、「非管理ユーザーが`DELETE`リクエスト（→`destroy`アクション）を送出しても、RDBのレコード件数は変化してはならない」というものです。コードは以下です。

```ruby:
assert_no_difference 'User.count' do
  delete user_path(@user)
end
```

しかしながら、管理者ユーザーのbeforeフィルターがコメントアウトされていると、「非管理ユーザーが`DELETE`リクエスト（→`destroy`アクション）を送出しても、RDBのレコード件数が変化する」という事態が発生してしまいます。

```
"User.count" didn't change by 0.
  Expected: 34
    Actual: 33
```

そのため、テストが失敗するのです。