Upgrade to Pro — share decks privately, control downloads, hide ads and more …

ActiveRecord scopeアンチパターン / ActiveRecord scope ...

ngmt
September 06, 2018

ActiveRecord scopeアンチパターン / ActiveRecord scope Antipatterns

https://omotesandorb.connpass.com/event/98377/
のLTで使用した資料です

ngmt

September 06, 2018
Tweet

More Decks by ngmt

Other Decks in Programming

Transcript

  1. ͸͡Ίʹ ͱ͋ΔUser model class User < ApplicationRecord has_many :articles has_many

    :comments scope :created_after, ->(time) { where('created_at >= ?', time) } scope :filter_by_abc, ->(a, b, c) { if a where(bbb: b).where(ccc: c) else where.not(bbb: b).where.not(ccc: c) end } scope :xxx, -> { … } scope :yyy {…} scope :zzz {…} scope : scope : … end ΤσΟλΛ։͍ͨTUWJFXʹ ໨తͷϝιου͕ͳ͍ େྔͷTDPQFͰݟ௨͕͠ѱ͍
  2. default scopeύλʔϯ class User < ApplicationRecord default_scope { where.not(archived_at: nil)

    } > User.all User Load (4.2ms) SELECT "users".* FROM "users" WHERE "users"."archived_at" IS NOT NULL LIMIT ? [["LIMIT", 11]] .rb ί ϯ ι ʛ ϧ
  3. SQLϕλॻ͖(or Arel)ύλʔϯ class Article < ApplicationRecord scope :anti_created_after, ->(time) {

    where('created_at >= ?', time) if time.present? } >Article.anti_created_after(0) Article Load (0.2ms) SELECT "articles".* FROM "articles" WHERE (created_at >= ‘0') LIMIT ? [["LIMIT", 11]] => #<ActiveRecord::Relation […]> ※datetimeͷΧϥϜΛจࣈྻͰߜΓࠐΊͯ͠·͏ɺ0ͩͱ΄΅શ෦͕֘౰͢Δ
  4. SQLϕλॻ͖(or Arel)ύλʔϯ class Article < ApplicationRecord scope :created_after, ->(time) {

    where(created_at: time..Time.current) } >Article.created_after(Time.current) >Article Load (0.2ms) SELECT "articles".* FROM "articles" WHERE "articles"."created_at" BETWEEN ? AND ? LIMIT ? [["created_at", "2018-09-06 11:07:01.342399"], ["created_at", "2018-09-06 11:07:01.342889"], ["LIMIT", 11]]
  5. ྨࣅscope૿৩ύλʔϯ class Article < ApplicationRecord scope :created_after, ->(time) { where(created_at:

    time..Time.current) } scope :anti_created_in_ten_years { where(created_at: (Time.current - 10.years)…Time.current) } scope :anti_created_in_a_year { where(created_at: (Time.current - 1.year)…Time.current) } scope :anti_created_in_a_month { where(created_at: (Time.current - 1.month)…Time.current) } scope :anti_created_in_a_week { where(created_at: (Time.current - 1.week)…Time.current) }
  6. ൚༻ੑߴ͗͢ύλʔϯ class Article < ApplicationRecord scope :anti_filter_by, ->(user, from, till,

    statuses) { written_by(user) .created_between(from, till) .filter_by_statuses(statuses) } scope :written_by, ->(user) { where(user: user) } scope :created_between, ->(from, till) { where(created_at: from..till) } scope :filter_by_statuses, ->(statuses) { where(status: statuses) } w Ҿ਺ͭΛࢦఆͯ͠ߜΓࠐΉέʔε ͸ଟ͍͔ʁ w Ҿ਺ͷਖ਼͠͞ΛνΣοΫ͢Δඞཁ ͸ͳ͍͔ʁ w νΣοΫ͢Δ৔߹JGͷࠞೖ΍৑௕ʹ ͳΒͳ͍͔ʁ w pMUFS@CZͱ͍͏໊લͰҙਤ͕఻Θ Δ͔ʁ
  7. finderྫ(ݸਓతͳझຯ) class ArticlesFinder def initialize(writer: nil, from: nil, till: nil,

    statuses: nil) @writer = writer @from = from @till = till @statuses = statuses end def find return @query if @query @query = Article @query = @query.eager_load(:user).written_by(@writer) if @writer if @from && @till @query = @query.created_between(@from, @till) else @query = @query.created_after(@from) if @from @query = @query.created_before(@till) if @till end @query = @query.where(status: @statuses) if @statuses @query end end