7
2

More than 1 year has passed since last update.

インスタンス変数を用いて処理を効率化する

Posted at

ログイン機能のアプリ作った際に、app/helpers/sessions_helper.rb
ファイルに以下のメソッドを定義しました。

module SessionsHelper
  def current_user
    @current_user ||@current_user = User.find_by(id: session[:user_id])
  end

  def logged_in?
    current_user.present?
  end
end

メソッドが呼び出されているviewファイル(app/views/layouts/application.html.erb)

<% if logged_in? %>
      <%= link_to "Profile", user_path(current_user.id) %>
      <%= link_to "Logout", session_path(current_user.id), method: :delete %>
 <% else %>
      <%= link_to "Sign up", new_user_path %>
      <%= link_to "Login", new_session_path %>
<% end %>

私はcurrent_userメソッドの@current_userがなぜインスタンス変数で定義されているかが分かりませんでした。current_userで定義したとしてもエラー等がなく、アプリは動きます。
しかし、メンターさん等の助けがあって、なぜ@current_userにしているか理由がわかりました。以下が詳細な説明になっています。

インスタンス変数とは

class A
  def b
    @a = 1
  end
  def c
    @a
  end
end
a = A.new
p a.b
p a.c

# 結果 @aが値を保持しています。
1
1

上記のような変数です。

app/helpers/sessions_helper.rbファイルのcurrent_userメソッド内の式を説明します。

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

上記の式は@current_userの中に値がなかった場合、User.find_by(id: session[:user_id])が実行されて、その結果が@current_userに入ります。
しかし@current_userの中に値があった場合は、User.find_by(id: session[:user_id])
は実行しません。

今回のケースはapp/views/layouts/application.html.erbファイルの中で、current_userメソッドが2回呼び出されています。インスタンス変数は値を保持することができるため、1回目で呼び出された時に、@current_user = User.find_by(id: session[:user_id])が行われ、2回目呼び出された時は、@current_userが値を既に持っているので、この処理(User.find_by(id: session[:user_id]))が行われません。
つまり、一回分処理が行われずに済んでいます。

ターミナル画面から確認しても処理が節約されている事がわかります。
app/helpers/sessions_helper.rbファイルで@current_userを使った場合

Started GET "/" for ::1 at 2022-10-13 14:42:22 +0900
Processing by SessionsController#new as HTML
  Rendering layout layouts/application.html.erb
  Rendering sessions/new.html.erb within layouts/application
  Rendered sessions/new.html.erb within layouts/application (Duration: 1.6ms | Allocations: 591)
[Webpacker] Everything's up-to-date. Nothing to do
  Rendered shared/_header.html.erb (Duration: 0.1ms | Allocations: 39)
  User Load (1.4ms)  SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT $2  [["id", 2], ["LIMIT", 1]]
  ↳ app/helpers/sessions_helper.rb:3:in `current_user'
  Rendered shared/_footer.html.erb (Duration: 0.2ms | Allocations: 38)
  Rendered layout layouts/application.html.erb (Duration: 81.0ms | Allocations: 3952)
Completed 200 OK in 97ms (Views: 80.6ms | ActiveRecord: 1.4ms | Allocations: 4465)

sqlが一度しか実行されていません。

7
2
1

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
7
2