LoginSignup
166
154

More than 5 years have passed since last update.

Rails Modelのscopeとlambda

Last updated at Posted at 2015-06-28

Modelのscopeとは?

Modelのscopeとは「共通のクエリの処理を設定し、それをメソッドのように使えるようにする機能」です。
例えば、下記のように公開日に達した記事だけを取り出すとします。

articles_controller.rb
class ArticlesController < ApplicationController
  def index
    @articles = Article.where("published_date < ?", Time.now())
  end
end

この公開日に達した時だけ取り出すという処理は何度も出てくるかもしれません。このときこの処理を共通処理としてまとめます。

articles_controller.rb
class ArticlesController < ApplicationController
  def index
    @articles = Article.published
  end
end
model/article.rb
class Article < ApplicationRecord
  scope :published, -> { where("published_date < ?", Time.now()) }
end

このように、.publishedをメソッドの要領で使うことが出来て便利です。
これがModelのscopeです。

Modelのscope使い方

上記にもあるように基本は

articles_controller.rb
class ArticlesController < ApplicationController
  def index
    @articles = Article.published
  end
end
model/article.rb
class Article < ApplicationRecord
  scope :published, -> { where("published_date < ?", Time.now()) }
end

のようにmodelにscopeを記述して使います。

引数を渡す

例えば、以下のようにある日時以降の記事を取り出したいとします。

articles_controller.rb
class ArticlesController < ApplicationController
  def index
    @articles = Article.where("published_date >", time)
  end
end

下記のように引数を渡せます。

articles_controller.rb
class ArticlesController < ApplicationController
  def index
    @articles = Article.published_after(Time.now())
  end
end
model/article.rb
class Article < ApplicationRecord
  scope :published_after, -> (time){ where("published_date >", time) }
end

scopeをmergeする

下記のように複数のscopeをマージすることが出来ます。

articles_controller.rb
class ArticlesController < ApplicationController
  def index
    @articles = Article.published.published_after(Time.now())
  end
end
model/article.rb
class Article < ApplicationRecord
  scope :published_after, -> (time){ where("published_date >", time) }
  scope :published, -> { where(published: true) }
end

defaultのscopeを設定する

defalut_scopeを使うと設定したModel内の全ての検索クエリにおいてそのscopeが適用されます。論理削除のときなどに使えます。

articles_controller.rb
class ArticlesController < ApplicationController
  def index
    @articles = Article.published_after(Time.now())
  end
end
model/article.rb
class Article < ApplicationRecord
  default_scope :published, -> { where(published: true) }
  scope :published_after, -> (time){ where("published_date >", time) }
end

アソシエーションを使うときにscopeを設定する

以下のように設定するとアソシエーションを使うときにscopeを適用できます。

class Article < ApplicationRecord
  has_many :comments, -> { order("updated_at DESC") }
end

この場合、commentsを更新日の新しい順に並べ替えます。

lambda ~->って何?~

->はlambda(ラムダ)記法で無名関数のような役割を果たします。
下記のRubyのコードを見るとどういう役割をしているか見えてきますね。

test = {
    hoge: ->(x) { x + 2 }
}
puts test[:hoge][3] # 5

参考

Rails ModelのScope(スコープ)の使い方(scopeメソッドとdefault_scopeメソッド)
Rubyのlambdaは無名関数では!?と気付き、調べた結果

166
154
8

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
166
154