search
LoginSignup
7

More than 1 year has passed since last update.

posted at

updated at

Organization

Rails6.1の新機能 Strict Loading について

本稿は、Ateam Finergy Inc. Advent Calendar2020の15日目の記事です。
本稿では、Rails6.1で新たに追加されたstrict_loadingについて解説します。

はじめに

strict_loadingは一言で言うと、N+1の発生を予防するためにActive Recordに導入された機能です。
以下のようなassociationのmodelがある場合、実際にどのようにして使うのか見ていきます。

app/models/user.rb
class User < ApplicationRecord
  has_many :posts
end
app/models/post.rb
class Post < ApplicationRecord
  belongs_to :user
end

メソッドとして使う

strict_loadingメソッドを使って取得したrecordでassociationを呼び出すと、以下のようにActiveRecord::StrictLoadingViolationErrorが発生します。

user = User.strict_loading.first
user.posts
 => ActiveRecord::StrictLoadingViolationError (`Post` called on `User` is marked for strict_loading and cannot be lazily loaded.)

includesなどEager loadingを行うメソッドでpostsを指定しておくと、問題なく呼び出すことができます。

user = User.includes(:posts).strict_loading.first
user.posts
=> #<ActiveRecord::Associations::CollectionProxy [#<Post id: 1, user_id: 1, title: "post_1", created_at: "2020-12-06 16:08:23.688506000 +0000", updated_at: "2020-12-06 16:08:23.688506000 +0000">, #<Post id: 2, user_id: 1, title: "post_2", created_at: "2020-12-06 16:08:23.696069000 +0000", updated_at: "2020-12-06 16:08:23.696069000 +0000">]>

上記のようにEager loadingを行うことが必須となるため、N+1の発生を予防することができます。

associationに定義する

strict_loadingは、associationを定義する際にもオプションとして指定することができます。

app/models/user.rb
class User < ApplicationRecord
  has_many :posts, strict_loading: true
end

こうしておくと、record取得の際にstrict_loadingメソッドを使わなくてもActiveRecord::StrictLoadingViolationErrorが発生します。

user = User.first
user.posts
=> ActiveRecord::StrictLoadingViolationError (`posts` called on `User` is marked for strict_loading and cannot be lazily loaded.)

model単位で指定する

association定義1つずつに指定するのが面倒な場合は、model単位で全てのassociationをまとめて指定することもできます。

app/models/user.rb
class User < ApplicationRecord
  self.strict_loading_by_default = true

  has_many :posts
end
user = User.first
user.posts
=> ActiveRecord::StrictLoadingViolationError (`Post` called on `User` is marked for strict_loading and cannot be lazily loaded.)

ログに出力する

ActiveRecord::StrictLoadingViolationErrorのエラーをraiseせずに、ログ出力することもできます。

config.active_record.action_on_strict_loading_violation = :log

デフォルトではエラーをraiseしますが、このようにconfigで各環境ごとにログ出力を指定できます。

Active Storageで使う

Active Storageのassociationであるhas_one_attachedhas_many_attachedに指定することもできます。

app/models/post.rb
class Post < ApplicationRecord
  belongs_to :user

  has_one_attached :logo, strict_loading: true
  has_many_attached :images, strict_loading: true
end

終わりに

N+1は、Railsのパフォーマンスを向上させる上で避けては通れない問題だと思います。
Rails6.1から新たに導入されたこのstrict_loadingを上手く活用することでN+1の発生を予防して、より高パフォーマンスのRailsアプリケーションが多く構築されることを願っております。

参考

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
What you can do with signing up
7