18
10

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

if current_user.admin? && !current_user?(user)で「!」が必要な理由

Last updated at Posted at 2020-02-04

##事象
railsチュートリアル「10.4.2 destroyアクション」において、
「現在のユーザーが管理者のときに限り」という条件を作るためにチュートリアルでは、下記のように記載されていました。

app/views/users/_user.html.erb
 <% if current_user.admin? && !current_user?(user) %>

2つの条件が成り立つ場合のif文になります。
右の条件において先頭に「!」が必要になる理由がわからなかったので記事にしました。
具体的には、現在のユーザーを「!」で否定すると条件が成り立たないのではと疑問に思っていました。

※左の条件は現在ブラウザを操作している自分が管理者権限を持つか判定しています。
※右の条件は後述していますが、現在ブラウザを操作している自分と同じユーザーかを判定しています。

##!の意味
!はnot演算子です。
式の値が真である時偽を、偽である時真を返します。

!true=>false !false=>true

##!current_user?(user)が何を表すか
current_user?の判定を「!」で逆転しています。
ここでは、
current_user?がtrueならfalseで返し、
current_user?がfalseならtrueで返します。

##忘れがちなeach文の存在
チュートリアルでややこしいことをやっているといま自分が何をやっているかわからなくなってしまうことが1周目だとちょくちょくありました。それゆえの失念だと思いますが、

そもそも、表題の条件文はeach文の中にあります。
下記がrender元のeach文です

app/views/users/index.html.erb
  <ul class="users">
     #省略型のeach文を表しています
   <%= render @users %>
  </ul>

下記がrender先になります。

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>

このためuserの部分にユーザーの全レコードがそれぞれ入れられていく処理になります。
するとif分の結果として下記の4通りあるはずです。

①真&&真(=管理者 かつ userがcurrent_user)
②真&&偽(=管理者 かつ userがcurrent_userではない)
③偽&&真(=非管理者 かつ userがcurrent_user)
④偽&&偽(=非管理者 かつ userがcurrent_userではない)

そして!current_user?(user)
この条件はeach分によって割り当てられたuserがcurrent_user(=ここでは現在ブラウザを見ている自分)と同じかを判定しています。
current_userで無い限り!falseとなり、結果trueになります。

初見ではちょっとわかりづらい部分かと思います。
成り立つのは②の「管理者 かつ userがcurrent_userではない」時のみになります。

※補足(20201106)
結果として以下の文によって、
ブラウザ上では、ユーザー一覧の内管理者である自分以外のユーザーの情報をdeleteするリンクを表示することになります。

<%= link_to "delete", user, method: :delete,data: { confirm: "You sure?" } %>

##まとめ
if current_user.admin? && !current_user?(user)
上記の文は管理者かつeach文によって割り当てられたuserが管理者(current_user)で無い限り成り立つことになります。

よって、管理者がユーザー一覧ページを開くと管理者以外のユーザーに対して削除ボタンを追加できるようになっています。
つまり管理者が自分自身を消せないようにもなっています。

##参考
https://docs.ruby-lang.org/ja/latest/doc/symref.html
https://teratail.com/questions/198416

18
10
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
18
10

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?