Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationEventAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
0
Help us understand the problem. What are the problem?
@koki0527

User.allを使わない。selectへ。

本記事の目的: モデルから取り出す際に、不要なデータ量を抑える

結論

user_controller.rb(変更前
:
def index
  @users = User.all.page(params[:page])
end

def following
  @title = "フォロー"
  @user = User.find(params[:id])
  @users = @user.following.page(params[:page])
  render "show_follow"
end
:
user_controller.rb(変更後
:
def index
  @users = User.select(:id, :username).
        includes([:works, avatar_attachment: :blob]).
        page(params[:page])
end

def following
  @title = "フォロー"
  @user = User.find(params[:id])
  @users = @user.following.select(:id, :username).
        includes([:works, avatar_attachment: :blob]).page(params[:page])
  render "show_follow"
end
:

本文

例の如くN+1問題の解消に取り掛かるべく、includesを用いて関連付けされているデータを同時に取り出す事で、クエリの発行を抑えていた。

そこでもう一つ。User.allの利用をやめることにした。理由としては、モデルから取り出す不要なデータ量を抑えるためである。解決方法としては、selectメソッドを用いることで、必要なデータだけを指定することとする。

具体例を以下に示します。

User.all
=>   TRANSACTION (0.4ms)  BEGIN
  User Load (0.8ms)  SELECT `users`.* FROM `users`
[#<User id: 1, username: "Test_User", email: "test@example.com", created_at: "2021-05-03 13:07:22.877662000 +0900", updated_at: "2021-05-03 13:07:58.184592000 +0900", uid: nil, provider: nil, description: "My name is Test_User", website: "http://example.com/">,
 #<User id: 2, username: "Mon Mothma", email: "test1@example.com", created_at: "2021-05-03 13:07:23.807304000 +0900", updated_at: "2021-05-03 13:07:58.296445000 +0900", uid: nil, provider: nil, description: "My name is Savage Opress", website: "http://example.com/">,
 :
 #<User id: 22, username: "Bail Organa", email: "test21@example.com", created_at: "2021-05-03 13:07:29.297810000 +0900", updated_at: "2021-05-03 13:07:29.297810000 +0900", uid: nil, provider: nil, description: "My name is Nute Gunray", website: "http://example.com/">]
User.select(:username, :id)
=>   User Load (1.3ms)  SELECT `users`.`username`, `users`.`id` FROM `users`
[#<User username: "Test_User", id: 1>,
 #<User username: "Mon Mothma", id: 2>,
 :
 #<User username: "Bail Organa", id: 22>]

以上のように結果は歴然であるが、必要なデータだけを取り出すことに成功した。ちなみにこれは、2行目にあるActiveRecordが発行するSQLの違いにより発生している。

User.all
=>   User Load (0.8ms)  SELECT `users`.* FROM `users`

User.select(:username, :id)
=>   User Load (1.3ms)  SELECT `users`.`username`, `users`.`id` FROM `users`

また、これは関連付けを行っているモデルにおいても同様の事が可能であった。

これもActiveRecordが発行するクエリに準じている事がわかる。

  pry(main)> user = User.first
  User Load (1.9ms)  SELECT `users`.* FROM `users` ORDER BY `users`.`id` ASC LIMIT 1
=> #<User id: 1, username: "Test_User", email: "test@example.com", created_at: "2021-05-03 13:07:22.877662000 +0900", updated_at: "2021-05-03 13:07:58.184592000 +0900", uid: nil, provider: nil, description: "My name is Test_User", website: "http://example.com/">

# 変更前
  pry(main)> user.following
=>   User Load (0.9ms)  SELECT `users`.* FROM `users` INNER JOIN `relationships` ON `users`.`id` = `relationships`.`followed_id` WHERE `relationships`.`follower_id` = 1
[#<User id: 3, username: "Lyra Erso", email: "test2@example.com", created_at: "2021-05-03 13:07:24.080580000 +0900", updated_at: "2021-05-03 13:07:58.435753000 +0900", uid: nil, provider: nil, description: "My name is Jango Fett", website: "http://example.com/">,
 #<User id: 4, username: "Borvo the Hutt", email: "test3@example.com", created_at: "2021-05-03 13:07:24.351829000 +0900", updated_at: "2021-05-03 13:07:58.993427000 +0900", uid: nil, provider: nil, description: "My name is Darth Sidious", website: "http://example.com/">,
 :
 #<User id: 21, username: "Mon Mothma", email: "test20@example.com", created_at: "2021-05-03 13:07:29.023478000 +0900", updated_at: "2021-05-03 13:07:29.023478000 +0900", uid: nil, provider: nil, description: "My name is Jango Fett", website: "http://example.com/">]

# 変更後
  pry(main)> user.following.select(:id, :username)
=>   User Load (1.7ms)  SELECT `users`.`id`, `users`.`username` FROM `users` INNER JOIN `relationships` ON `users`.`id` = `relationships`.`followed_id` WHERE `relationships`.`follower_id` = 1
[#<User id: 3, username: "Lyra Erso">,
 #<User id: 4, username: "Borvo the Hutt">,
 :
 #<User id: 21, username: "Mon Mothma">]

以上です!

最後まで読んで頂きありがとうございました!

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
0
Help us understand the problem. What are the problem?