すでにメンバーの場合は

無料会員登録

GitHubアカウントで登録 Pikawakaが許可なくTwitterやFacebookに投稿することはありません。

登録がまだの方はこちらから

Pikawakaにログイン

GitHubアカウントでログイン Pikawakaが許可なくTwitterやFacebookに投稿することはありません。

Rails

公開日:  |  最終更新日:

【Rails】 モデルのスコープ機能(scope)の使い方を1から理解する

ぴっかちゃん
ぴっかちゃん

モデルのスコープ機能とは、モデル側であらかじめ特定の条件式に対して名前をつけて定義し、その名前でメソッドの様に条件式を呼び出すことが出来る仕組みのことです。

対象モデルクラス | 基本構文
1
2
3
class モデル名 < ApplicationRecord
  scope :スコープの名前, -> { 条件式 }
end

例えば、publishedという名前に公開記事を取得する条件式を定義するには、以下のように記述します。

app/models/blog.rb | scopeメソッドで公開記事を取得する条件式を定義する
1
2
3
class Blog < ApplicationRecord
    scope :published, -> { where(published: true) }
end

定義したスコープは以下のように呼び出す事が出来ます。

Blogモデルに定義したスコープのpublishedを使用する場合
1
Blog.published

スコープ機能の基礎知識

この章では、モデルのスコープ機能の基礎知識について解説します。

スコープ機能のメリットとは?

スコープ機能を使う事によって、下記の様なメリットがあります。

  1. 条件式に名前を付けられるので、直感的なコードになる
  2. 修正箇所を限定することが出来る
  3. コードが短くなる

記事を管理しているblogsテーブルを使って、スコープ機能のメリットを確認していきましょう。

blogsテーブル

blogsテーブルから公開記事を取得するには、Blogモデルに対してwhere(published: true)の条件式を使います。この条件式に対して、publishedの名前を付けてscopeメソッドで定義すると下記の様になります。

モデル | 公開記事を取得する条件式にscopeメソッドで定義する-->
1
2
3
class Blog < ApplicationRecord
    scope :published, -> { where(published: true) }
end

このpublishedのスコープを使って、スコープを使用した場合・使用しなかった場合を比較していきます。

1. 条件式に名前を付けられるので、直感的なコードになる

スコープ機能を使うと、条件式に対して名前を付けられるので直感的なコードになります。

先ほど定義したスコープによって、公開記事を取得するwhere(published: true) の条件式をpublishedの名前で呼び出すことが出来ます。

スコープ機能を使わない場合
1
Blog.where(published: true)
スコープ機能を使う場合
1
Blog.published

スコープ機能を使うことによって、コードが直感的で簡潔になっていることが分かります。

2. 修正箇所を限定することが出来る

条件式に変更が出た場合に、修正がscopeメソッドで定義した箇所だけで済みます。
例えば、公開記事を取得する上限を2件までにしたい場合は、下記の様にscopeメソッドで定義した箇所にlimit(2)を加えるだけで済みます。

blog.rb | 条件式にlimitを追加する -->
1
2
3
class Blog < ApplicationRecord
  scope :published, -> { where(published: true).limit(2) } # limitを追加
end

scopeメソッドを使わない場合は、where(published: true)の全ての箇所にlimitを追加する必要があります。

Controller | scopeメソッドを使わない場合-->
1
2
3
4
5
6
7
def index
  @published_blogs = Blog.where(published: true).limit(2) # limitを追加 
end

def test
  @published_blogs = Blog.where(published: true).limit(2) # limitを追加 
end

3. コードが短くなる

スコープ機能は、クラスメソッドでも代用可能ですが、scopeメソッドで定義すると1行でコードを記述することが出来ます。

blog.rb | scopeメソッドを使った場合は、1行で済む -->
1
2
3
4
class Blog < ApplicationRecord
  # この1行で済む
  scope :published, -> { where(published: true).limit(2) }
end

クラスメソッドで定義すると、最低3行は必要になります。

blog.rb | クラスメソッドで定義する場合 -->
1
2
3
4
5
6
class Blog < ApplicationRecord
  # 最低3行は必要
  def self.published
    where(published: true).limit(2)
  end
end

それでは、scopeメソッドの定義方法と基本的な使い方を解説していきます。

scopeメソッドの基本的な使い方

scopeメソッドの第一引数に条件式を呼び出すための名前、第二引数に条件式を実装するlambdaを渡します。

対象モデルクラス | scopeメソッドの第一引数に呼び出すための名前、第二引数には条件式を定義する -->
1
2
3
class モデル名 < ApplicationRecord
  scope :スコープの名前, -> { 条件式 }
end
  • 第一引数は、シンボル(:)を使ってスコープの名前を指定します。
  • 第二引数の->{条件式}のlambdaは、処理の中でメソッドを定義してくれる手法です。

※第二引数のlambdaは、->{}の中に条件式を記述することが出来るとだけ覚えておきましょう。

引数を使う

scopeメソッドは、下記の様に->の後に引数を定義することで、引数を渡すことが出来ます。

対象モデルクラス | scopeメソッドに引数を使った場合 -->
1
2
3
class モデル名 < ApplicationRecord
  scope :スコープの名前, -> (引数){ 条件式 } 
end

先ほど公開記事を取得する際には、limit(2)によって最大2つまでの取得に固定されていましたが、取得する記事の上限をその都度変更したい場合は、下記の様に引数countをscopeメソッドに定義します。

blog.rb | scopeメソッドに引数を使用した場合の比較 -->
1
2
3
4
5
6
7
class Blog < ApplicationRecord  # 引数を使用しない場合
  scope :published, -> { where(published: true).limit(2) } 
end

class Blog < ApplicationRecord # 引数を使用した場合
  scope :published, -> (count){ where(published: true).limit(count) }
end

これによって、Blog.published(値)で公開記事の最大取得数を変更することが出来ます。引数に3を渡して実行してみましょう。

コンソール | publishedの引数に3を入れて実行する-->
1
2
3
4
5
6
7
Blog.published(3)
SELECT  `blogs`.* FROM `blogs`  WHERE `blogs`.`published` = 1 LIMIT 3

=> #<ActiveRecord::Relation [ # 返り値
#<Blog id: 1, url: "ruby", title: "rubyとは?", published: true, created_at: "2019-12-05 15:08:25", updated_at: "2019-12-05 15:08:25">, 
#<Blog id: 3, url: "sketch", title: "sketchの使い方", published: true, created_at: "2019-12-07 17:10:55", updated_at: "2019-12-07 17:10:55">,
 #<Blog id: 4, url: "gem", title: "gemとは?", published: true, created_at: "2019-12-08 15:30:00", updated_at: "2019-12-08 15:30:00">]>

返り値で公開記事を3件取得出来ているのが確認できます。この様に引数を使うことで、汎用性のある条件式を組み立てることが出来ます。

メリットの所でもscopeメソッドで定義すると「修正する箇所を限定出来る」と解説しましたが、scopeメソッドを使わないで条件式を変更する場合は、全ての箇所の修正が必要になります。

もしscopeメソッドを使わないで、複数の箇所に同じ条件式を記述した場合は、

コントローラ | 複数の箇所に同じ条件式を記述した場合-->
1
2
3
4
5
def index
  Blog.where(published: true).limit(3)
  Blog.where(published: true).limit(3)
  Blog.where(published: true).limit(3)
end

となりますが、この条件式に降順で取得するorder(id: desc)を追加したければ1つ1つのBlog.where(published: true).limit(3)に対して

コントローラ | scopeメソッドを使わない場合の修正箇所 -->
1
2
3
4
5
def index
  Blog.where(published: true).limit(3).order(id: desc) # orderメソッド追加
  Blog.where(published: true).limit(3).order(id: desc) # orderメソッド追加
  Blog.where(published: true).limit(3).order(id: desc) # orderメソッド追加
end

にする必要があります。

しかし、scopeメソッドで定義してあれば、

blog.rb | scopeメソッドを使った場合の修正箇所 -->
1
2
3
class Blog < ApplicationRecord
  scope :published, -> (count){ where(published: true).limit(count).order(id: desc)  # ここに追加するだけ}
end

の様に1箇所の修正で済みます。scopeメソッドで定義すると修正箇所が限定されて、修正漏れを防ぎやすくなります。

条件文を使う

scopeメソッドは、if文を使って処理を分岐することが出来ます。例えば、blogの件数は現在5件しかありませんので、最大取得記事数を5未満に制限します。

下記は、引数で渡される値が5未満の場合はその値の記事数を取得する事が出来て、5を超える場合は5件以上はないので全件(5件)取得します。

blog.rb | 引数のcountが5未満ならクエリを実行するという条件文を追加する -->
1
2
3
class Blog < ApplicationRecord
  scope :published, -> (count){ where(published: true).limit(count) if count < 5 }
end

引数に2を渡した場合は、2つの公開記事のデータを取得する事が出来ています。しかし、引数に50を渡した場合は、全件取得されている事が確認出来ます。

コンソール | 引数に渡される値が5未満の場合-->
1
2
3
4
5
6
Blog.published(2)
SELECT  `blogs`.* FROM `blogs`  WHERE `blogs`.`published` = 1 LIMIT 2

=> #<ActiveRecord::Relation [ # 返り値
#<Blog id: 1, url: "ruby", title: "rubyとは?", published: true, created_at: "2019-12-05 15:08:25", updated_at: "2019-12-05 15:08:25">, 
#<Blog id: 3, url: "sketch", title: "sketchの使い方", published: true, created_at: "2019-12-07 17:10:55", updated_at: "2019-12-07 17:10:55">]>
引数に渡される値が5を超える場合 -->
1
2
3
4
5
6
7
8
9
Blog.published(50)
SELECT `blogs`.* FROM `blogs`

=> #<ActiveRecord::Relation [ # 返り値
#<Blog id: 1, url: "ruby", title: "rubyとは?", published: true, created_at: "2019-12-05 15:08:25", updated_at: "2019-12-05 15:08:25">, 
#<Blog id: 2, url: "bundle", title: "bundlerとは?", published: false, created_at: "2019-12-06 15:10:05", updated_at: "2019-12-06 15:10:05">, 
#<Blog id: 3, url: "sketch", title: "sketchの使い方", published: true, created_at: "2019-12-07 17:10:55", updated_at: "2019-12-07 17:10:55">, 
#<Blog id: 4, url: "gem", title: "gemとは?", published: true, created_at: "2019-12-08 15:30:00", updated_at: "2019-12-08 15:30:00">, 
#<Blog id: 5, url: "scope", title: "scopeとは?", published: false, created_at: "2019-12-09 11:08:00", updated_at: "2019-12-09 11:08:00">]>

引数に50を渡した場合に全件取得していた理由は、scopeメソッドは条件文が評価された結果がfalseを返す時はallメソッドを返して全てのレコードを取得するからです。(後ほど詳しく解説します。)

スコープ機能の応用知識

この章では、スコープ機能の応用的な使い方からクラスメソッドとの違いについて解説します。

scopeメソッドの応用的な使い方

scopeメソッドは、下記の様にスコープに対してメソッドチェーンを使って他のクエリメソッドや別のスコープを呼び出すことが出来ます。

コンソール | publishedのスコープに対してメソッドチェーンでorderメソッドを呼び出す -->
1
2
3
4
5
6
Blog.published.order(id: :desc)
SELECT  `blogs`.* FROM `blogs`  WHERE `blogs`.`published` = 1  ORDER BY `blogs`.`id` DESC LIMIT 2

=> #<ActiveRecord::Relation [ # 返り値
#<Blog id: 4, url: "gem", title: "gemとは?", published: true, created_at: "2019-12-08 15:30:00", updated_at: "2019-12-08 15:30:00">,
 #<Blog id: 3, url: "sketch", title: "sketchの使い方", published: true, created_at: "2019-12-07 17:10:55", updated_at: "2019-12-07 17:10:55">]>

scopeメソッドの応用的な使い方をマスターする為に、メソッドチェーンや返り値を理解していきましょう。

メソッドチェーンについて

メソッドチェーンは、あるオブジェクトに対して.(ドット)でメソッドを繋げます。そして、.(ドット)の次に繋げたメソッドが .(ドット)の前のメソッドの返り値を受け取って処理していきます。

コンソール | publishedのスコープに対してメソッドチェーンでorderメソッドを呼び出す -->
1
Blog.published.order(id: :desc)

上記のコードをメソッドチェーンの流れに当てはめると、下記の意味になります。

  1. Blogオブジェクトに対して.(ドット)でpublishedスコープを繋げます。
  2. .(ドット)の前のpublishedスコープで返り値を.(ドット)の次に繋げたorderメソッドが受け取って処理していきます。

メソッドチェーンは、返り値がActiveRecord::Relationオブジェクトに対して使うことが出来ます。

返り値について(ActiveRecord::Relation)

scopeメソッドの返り値は、常にActiveRecord::Relationオブジェクトを返します。

下記のpublishedスコープを実行すると、ActiveRecord::Relationオブジェクトが返り値となっている事が確認出来ます。

コンソール | publishedのスコープの返り値は、ActiveRecord::Relationオブジェクト-->
1
2
3
4
5
6
7
Blog.published(3)
SELECT  `blogs`.* FROM `blogs`  WHERE `blogs`.`published` = 1 LIMIT 3

=> #<ActiveRecord::Relation [ # 返り値
#<Blog id: 1, url: "ruby", title: "rubyとは?", published: true, created_at: "2019-12-05 15:08:25", updated_at: "2019-12-05 15:08:25">, 
#<Blog id: 3, url: "sketch", title: "sketchの使い方", published: true, created_at: "2019-12-07 17:10:55", updated_at: "2019-12-07 17:10:55">,
 #<Blog id: 4, url: "gem", title: "gemとは?", published: true, created_at: "2019-12-08 15:30:00", updated_at: "2019-12-08 15:30:00">]>

scopeメソッドの最大の特徴は、scopeメソッドの返り値がActiveRecord::Relationオブジェクトになる事なので覚えておきましょう。

nilの場合について

scopeメソッドは、scopeメソッドで定義した条件式がnilを返す場合は、allメソッドを実行します。allメソッドの返り値は、ActiveRecord::Relationオブジェクトです。

つまり、scopeメソッドで定義した条件式がnilを返す場合でも、ActiveRecord::Relationオブジェクトを返します。(※条件式の中のif文がfalseを返す場合も同様の挙動です。)

publishedスコープの条件式をnilに変更してBlog.publishedを実行すると、blogsテーブルの全レコードが取得されます。

blog.rb | publishedスコープの条件式をnilに変更-->
1
2
3
class Blog < ApplicationRecord
  scope :published, -> { nil } # 条件式をnilに変更
end
スコープがnilを返す場合に、allメソッドが実行される -->
1
2
3
4
5
6
7
8
9
Blog.published
SELECT `blogs`.* FROM `blogs`

=> #<ActiveRecord::Relation [ # 返り値
#<Blog id: 1, url: "ruby", title: "rubyとは?", published: true, created_at: "2019-12-05 15:08:25", updated_at: "2019-12-05 15:08:25">,
 #<Blog id: 2, url: "bundle", title: "bundlerとは?", published: false, created_at: "2019-12-06 15:10:05", updated_at: "2019-12-06 15:10:05">, 
#<Blog id: 3, url: "sketch", title: "sketchの使い方", published: true, created_at: "2019-12-07 17:10:55", updated_at: "2019-12-07 17:10:55">, 
#<Blog id: 4, url: "gem", title: "gemとは?", published: true, created_at: "2019-12-08 15:30:00", updated_at: "2019-12-08 15:30:00">, 
#<Blog id: 5, url: "scope", title: "scopeとは?", published: false, created_at: "2019-12-09 11:08:00", updated_at: "2019-12-09 11:08:00">]>

scopeメソッドの条件式がnilを返す場合でもActiveRecord::Relationオブジェクトを返すので、scopeメソッドで定義したスコープに対して、常にメソッドチェーンを使う事が出来ます。

コンソール | publishedのスコープに対してメソッドチェーンでorderメソッドを呼び出す -->
1
2
3
4
5
6
7
8
9
Blog.published.order(id: :desc)
SELECT `blogs`.* FROM `blogs`   ORDER BY `blogs`.`id` DESC

=> #<ActiveRecord::Relation [ # 返り値
#<Blog id: 5, url: "scope", title: "scopeとは?", published: false, created_at: "2019-12-09 11:08:00", updated_at: "2019-12-09 11:08:00">, 
#<Blog id: 4, url: "gem", title: "gemとは?", published: true, created_at: "2019-12-08 15:30:00", updated_at: "2019-12-08 15:30:00">, 
#<Blog id: 3, url: "sketch", title: "sketchの使い方", published: true, created_at: "2019-12-07 17:10:55", updated_at: "2019-12-07 17:10:55">, 
#<Blog id: 2, url: "bundle", title: "bundlerとは?", published: false, created_at: "2019-12-06 15:10:05", updated_at: "2019-12-06 15:10:05">, 
#<Blog id: 1, url: "ruby", title: "rubyとは?", published: true, created_at: "2019-12-05 15:08:25", updated_at: "2019-12-05 15:08:25">]>

上記のコードはエラーが起きる事なく、publishedのスコープに対してメソッドチェーンでorderメソッドを呼び出す事が出来ています。

メソッドチェーンで連結して、データを取得してみよう

先ほどはpublishedのスコープにメソッドチェーンでorderメソッドを呼び出していましたが、別のスコープも呼び出す事も出来ます。recentsearch_with_titleのスコープを追加して確認してみましょう。

blog.rb | 複数のスコープをblogs追加-->
1
2
3
4
5
class Blog < ApplicationRecord
    scope :recent, -> { order(id: :desc) }
    scope :published, ->(count)  { where(published: true).limit(count) if count < 5 }
    scope :search_with_title, ->(title) { where(title: title) }
end
コンソール | 複数のスコープをメソッドチェーンで連結-->
1
2
3
4
5
6
Blog.published(2).search_with_title(['rubyとは?', 'gemとは?']).recent
SELECT  `blogs`.* FROM `blogs`  WHERE `blogs`.`published` = 1 AND `blogs`.`title` IN ('rubyとは?', 'gemとは?')  ORDER BY `blogs`.`id` DESC LIMIT 2

=> #<ActiveRecord::Relation [ # 返り値
#<Blog id: 4, url: "gem", title: "gemとは?", published: true, created_at: "2019-12-08 15:30:00", updated_at: "2019-12-08 15:30:00">, 
#<Blog id: 1, url: "ruby", title: "rubyとは?", published: true, created_at: "2019-12-05 15:08:25", updated_at: "2019-12-05 15:08:25">]>

複数のスコープを連結していますが、発行されるSQLは1回のみです。
これはクエリメソッドの遅延ロードと呼ばれるもので、データが必要になって初めてデータベースに問い合わせるからです。1回のSQLの発行で済むのでパフォーマンスも良くなります。

SQL | 発行されたSQL文
1
2
3
4
SELECT  `blogs`.*
  FROM `blogs`  
  WHERE `blogs`.`published` = 1 AND `blogs`.`title` IN ('rubyとは?', 'gemとは?')  
  ORDER BY `blogs`.`id` DESC LIMIT 2

上記のSQLのWHERE句では、blogs.published = 1blogs.title IN ('rubyとは?', 'gemとは?')の間に条件を絞り込むANDがあります。ANDは、どちらの条件も満すという意味で、「published列の値が1(true)」かつ「タイトルが'rubyとは?'と 'gemとは?'」の条件を満たしたレコードを取得します。

このようにメソッドチェーンでメソッドや別のスコープを呼び出すことで、より複雑なデータ検索ができます。

scopeメソッドのスコープ定義のポイント
  1. scopeメソッドの返り値は、ActiveRecord::Relationオブジェクトを常に返す
  2. scopeメソッドで定義したクエリがnilを返す場合は、.allを返す
  3. 必ずメソッドチェーンを使うことできる

スコープとクラスメソッドの違い

ここまでscopeメソッドの定義方法について解説してきましたが、クラスメソッドでも同じように定義できます。「対象モデル.クラスメソッド名」で定義した条件式を呼び出す事が出来ます。

対象モデルクラス | クラスメソッドの定義方法-->
1
2
3
4
5
class モデル名 < ApplicationRecord
  def self.メソッド名
    条件式
  end
end

scopeメソッドとクラスメソッドは、nilを返す時の挙動が違います。

  • scopeメソッドはnilの場合にallメソッドが実行されるので、メソッドチェーンを使う事ができる
  • クラスメソッドはnilの場合はnilが返るので、メソッドチェーンを使う事が出来ない。

それでは、クラスメソッドの返り値やnilの場合の挙動を確認していきましょう。

返り値について(ActiveRecord::Relation)

クラスメソッドで定義した条件式が正常に評価された場合は、ActiveRecord::Relationオブジェクトが返ります。publishedクラスメソッドに、最大2つの公開記事を取得する条件式を定義してBlog.publishedを実行していきます。

blog.rb | publishedクラスメソッドに条件式を定義-->
1
2
3
4
5
class Blog < ApplicationRecord
  def self.published
    where(published: true).limit(2)
  end
end
コンソール | クラスメソッドのpublishedを呼び出す-->
1
2
3
4
5
6
Blog.published
SELECT  `blogs`.* FROM `blogs`  WHERE `blogs`.`published` = 1 LIMIT 2

=> #<ActiveRecord::Relation [ # 返り値
#<Blog id: 1, url: "ruby", title: "rubyとは?", published: true, created_at: "2019-12-05 15:08:25", updated_at: "2019-12-05 15:08:25">, 
#<Blog id: 3, url: "sketch", title: "sketchの使い方", published: true, created_at: "2019-12-07 17:10:55", updated_at: "2019-12-07 17:10:55">]>

返り値は、ActiveRecord::Relationオブジェクトになります。返り値がActiveRecord::Relationオブジェクトなので、publishedクラスメソッドに対してもメソッドチェーンを使って他のメソッドや別のスコープを呼び出す事が可能です。

メソッドチェーンを使って、orderメソッドを呼び出す -->
1
2
3
4
5
6
Blog.published.order(id: :desc)
SELECT  `blogs`.* FROM `blogs`  WHERE `blogs`.`published` = 1  ORDER BY `blogs`.`id` DESC LIMIT 2

=> #<ActiveRecord::Relation [ # 返り値
#<Blog id: 4, url: "gem", title: "gemとは?", published: true, created_at: "2019-12-08 15:30:00", updated_at: "2019-12-08 15:30:00">, 
#<Blog id: 3, url: "sketch", title: "sketchの使い方", published: true, created_at: "2019-12-07 17:10:55", updated_at: "2019-12-07 17:10:55">]>

この様にクラスメソッドでも、返り値がActiveRecord::Relationオブジェクトの場合はメソッドチェーンを使う事が出来ます。

nilの場合について

クラスメソッドで定義した条件式がnilを返す場合の返り値は、nilが返るのでメソッドチェーンを使う事が出来ません。この状態でメソッドチェーンを使うとNoMethodErrorが発生します。

publishedクラスメソッドの条件式をnilに変更してBlog.publishedを実行します。

blog.rb | publishedクラスメソッドの条件式をnilに変更-->
1
2
3
4
5
class Blog < ApplicationRecord
  def self.published
    nil # 変更
  end
end
publishedクラスメソッドを呼び出す-->
1
2
Blog.published
=> nil # 返り値

コード実行後の返り値は、nilが返ります。この状態で、メソッドチェーンを使ってorderメソッドを呼び出してみましょう。

コンソール | publishedメソッドの返り値がnilの場合-->
1
2
Blog.published.order(id: :desc)
NoMethodError: undefined method `order' for nil:NilClass

返り値がnilに対してorderメソッドを実行しているので、NoMethodErrorが発生します。この様にscopeメソッドで定義した時とは違い、クラスメソッドはロジックがnilを返す場合は、nilが返るのでメソッドチェーンを使う場合は注意が必要です。

引数を使う場合は、クラスメソッドの方が推奨される

scopeメソッドの引数は、クラスメソッドの機能を複製させたものなので、引数を使う場合はクラスメソッドを使う方が推奨されます。(Ruby on Rails Guidesより)

publishedクラスメソッドに引数countを追加して、取得する記事数を変更できる様にします。最大3つの公開記事のデータを取得してみましょう。

blog.rb | クラスメソッドで引数を使う-->
1
2
3
4
5
class Blog < ApplicationRecord
    def self.published(count)
        where(published: true).limit(count)
    end
end
blog.rb | 最大3つの公開記事のデータを取得する-->
1
2
3
4
5
6
7
Blog.published(3)
SELECT  `blogs`.* FROM `blogs`  WHERE `blogs`.`published` = 1 LIMIT 3

=> #<ActiveRecord::Relation [ # 返り値
#<Blog id: 1, url: "ruby", title: "rubyとは?", published: true, created_at: "2019-12-05 15:08:25", updated_at: "2019-12-05 15:08:25">, 
#<Blog id: 3, url: "sketch", title: "sketchの使い方", published: true, created_at: "2019-12-07 17:10:55", updated_at: "2019-12-07 17:10:55">, 
#<Blog id: 4, url: "gem", title: "gemとは?", published: true, created_at: "2019-12-08 15:30:00", updated_at: "2019-12-08 15:30:00">]>

しかし、クラスメソッドは前述した様にロジックがnilを返す場合はscopeメソッドとは違いnilが返ってきます。もしメソッドチェーンを使っていればNoMethodErrorのエラーが発生する場合があるので注意してください。

クラスメソッドのスコープ定義のポイント
  1. クラスメソッドのロジックがnilを返す時の返り値は、nilになります。
  2. クラスメソッドの返り値がnilの場合は、メソッドチェーンを使って他のメソッドやクエリを使うとNoMethodErrorのエラーが発生します。

この記事のまとめ

  • scopeメソッドを使うと、条件式に名前を付けてメソッドの様に呼び出すことが出来る
  • scopeメソッドの返り値は、ActiveRecord::Relationオブジェクトを常に返す
  • クラスメソッドでロジックがnilやfalseを返す場合は、返り値がnilになるのでメソッドチェーンを使う事が出来ない