shun_study_p
@shun_study_p

Are you sure you want to delete the question?

Leaving a resolved question undeleted may help others!

[rails tutorial 第8章] 8.2.2 現在のユーザーに関して質問です

rails tutorial 第8章

8.2.2 現在のユーザー

こちらのトピックで分からないことがあります。

わからない事

こちらの

#current_userメソッドの定義
def current_user
  if session[:user_id]
    User.find_by(id: session[:user_id])
  end
end

はなぜ、

#ユーザーIDが存在しない場合例外が返る
User.find(session[:user_id])

ではなく

#ユーザーが存在しない場合nilが返る
User.find_by(id: session[:user_id])

とするべきなのでしょうか?


本文より
セッションにユーザーIDが存在しない場合findメソッド使用すると例外が発生する事は理解しました。
また
セッションにユーザーIDが存在しない場合find_byメソッドを使用するとnilが返ることも理解しています。

しかしcurrent_userメソッドでは

if session[:user_id]
  ...
end

とすることでログインしているユーザーが存在しない場合、自動的にnilが返っているように思います。

それならばif文内が実行されるのはログインしているユーザーがいる時に限られると思うので、その中のコードが

User.find(session[:user_id])

でも

User.find_by(id: session[:user_id])

そこまで変わりがない様に思います。


考えてみたこと


session[:user_id]
には存在する値があるがUser.find(session[:user_id])
に対応するユーザーが存在しないケースがある?

#findを使用したcurrent_userメソッドの定義
def current_user
  if session[:user_id]
    User.find(session[:user_id])
  end
end

は、たとえ

if session[:user_id]
  ...
end

としてif文によってユーザーが存在していることを確かめ、最終的にユーザーを取り出せたとしても単にfindよりもfind_byを使用するべきとされていて相応しくないから?


ご助言お待ちしております。

0

2Answer

多分

def current_user
  User.find_by(id: session[:user_id])
end

としてもいいけど、

current_userメソッドが1リクエスト内の処理で何度も呼び出されてしまうと、呼び出された回数と同じだけデータベースへの問い合わせが発生してしまい、結果として処理が完了するまでに時間がかかってしまうからです。

というのが理由ではないですかね?

1Like

Comments

  1. @shun_study_p

    Questioner

    github0013@github様

    ご回答ありがとうございます。

    ご助言いただいた部分に関しては私も以下の様に理解しております。

    ---

    データベースへの無用な問い合わせを避ける為に
    #セッションにユーザーが存在するかを確かめる

    if session[:user_id]
    ...
    end

    と言うif文を設定する。
    そうする事でセッションにユーザーが存在しない時はif文内は実行されず、余計なデータベースへの問い合わせは行われない。

    ---

    私のわからなかった所はそのif文内のコードの方でした。
    if文によりユーザーの存在を確かめているのであればfindメソッドでもfind_byメソッドでも対応するユーザーは取り出せるのでは?
    と考えてしまいまして、、、

    幸い他の方にもご回答いただき今回の質問に関しては解決することができました。

    改めてご助言ありがとうございました!

session[:user_id]
には存在する値があるがUser.find(session[:user_id])
に対応するユーザーが存在しないケースがある?

普通はログイン時には存在する User レコードを元にsession[:user_id] をセットしますし、ユーザーの退会ロジックでは User レコードを消すと同時にセッションも削除します。あまり考慮しなくていいケースではあります。

ただ、実装ミスか何かでそんなケースに陥る可能性はあります。レアケースでだけ current_user が例外を投げるようになっていると、例外の rescue を忘れがちです。 User.find は RecordNotFound 例外を投げますから、ユーザーはセッションが切れてそのケースから抜け出すまで(≒ユーザーのクッキーが失効するか自身で消すまで)どのページにアクセスしても404画面に飛ばされることになります。そうなっては困りますね。

def current_user
  if session[:user_id]
    User.find_by(id: session[:user_id])
  end
end

このように User.find_by を使っておけば、そんなケースでもただ nil が返るので、ログインしていない状態と同じように処理を続行できます。

セッションがあるのに User オブジェクトがない状態を判別したいからあえて User.find を使うという選択もあります。そこは実装方針次第です。

1Like

Comments

  1. @shun_study_p

    Questioner

    uasi様

    ご回答ありがとうございます!

    とてもわかり易く納得のいく回答を得ることが出来ました!
    ご指摘いただいた様なレアケースがあるのでしたらやはり今回はnilを返すfind_byメソッドの方が相応しいと良く理解出来ました。

    実装次第でfindメソッドを使用すると言う選択もあり。
    と言う事もとても勉強になりました!

    改めてありがとうございました!

Your answer might help someone💌