Slide 1

Slide 1 text

ActiveRecord scope Ξϯνύλʔϯ

Slide 2

Slide 2 text

ࣗݾ঺հ • Rails ϝΠϯͷΤϯδχΞ • ग़ࣗ͸ශ๡ࢠ୔ࢁ͠·ΜͪΎ • @ngmt83 Ҏ্ʂ

Slide 3

Slide 3 text

֓ཁ • ࣗݾ঺հ • ͸͡Ίʹ • Ξϯνύλʔϯ • ϕλʔͳํ਑ • RailΛ৳͹͢ϊ΢ϋ΢, ࢀߟࢿྉ

Slide 4

Slide 4 text

͸͡Ίʹ model͸Ͳ͏଍ૡ͍ͯ΋ϑΝοτʹͳΔ Մಡੑ͕མͪͯ͘Δ ͦΕͰ΋Ͳ͏ʹ͔͍ͨ͠ ࠓճ͸scopeʹ஫໨͠·͢

Slide 5

Slide 5 text

͸͡Ίʹ ͱ͋Δ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Ͱݟ௨͕͠ѱ͍

Slide 6

Slide 6 text

Ξϯνύλʔϯ • default scopeύλʔϯ • SQLϕλॻ͖(or Arel)ύλʔϯ • ྨࣅscope૿৩ύλʔϯ • ൚༻ੑߴ͗͢ύλʔϯ

Slide 7

Slide 7 text

આ໌ʹ࢖༻͢ΔERD

Slide 8

Slide 8 text

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 ί ϯ ι ʛ ϧ

Slide 9

Slide 9 text

default scopeύλʔϯ • ʮdefault scopeΛ֎͢͜ͱ͸͋Γ͑ͳ͍ʯ →͋Γ͑ͳ͍ͳΜͯ͋Γ͑ͳ͍ • Α͋͘Δྫ Ϣʔβʹ͸ݟ͑ͳ͍͍͚ͯ͘Ͳɺ؅ཧऀతʹ͸ σʔλूܭͱ͔Ͱɺݟ͑ͨํ͕͍͍

Slide 10

Slide 10 text

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]] => # ※datetimeͷΧϥϜΛจࣈྻͰߜΓࠐΊͯ͠·͏ɺ0ͩͱ΄΅શ෦͕֘౰͢Δ

Slide 11

Slide 11 text

SQLϕλॻ͖(or Arel)ύλʔϯ • railsͷmodelͱRDBͷtableߏ଄͕ີ݁߹ʹͳͬͯ͠·͏ • ଞͷscopeͱ૊Έ߹Θͤͯͷ࢖༻͕͠ʹ͍͘ • Մಡੑ͕௿͍ • Arelʹ͍ͭͯ • ॻ͍ͨਓ͸࢖͍͜ͳͤΔ͔΋͠Εͳ͍͕ɺͦͷΑ͏ͳਓ ͸ଟ͘ͳ͍ɻSQLΛ࢖͍͜ͳͤΔਓͷ΄͏͕·ͩଟ͍

Slide 12

Slide 12 text

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]]

Slide 13

Slide 13 text

ྨࣅ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) }

Slide 14

Slide 14 text

ྨࣅscope૿৩ύλʔϯ • ৑௕ →࢖༻ස౓͕͍͘Βߴ͘ͱ΋େ఍͸Ҿ਺ͰͲ͏ ʹ͔͢΂͖

Slide 15

Slide 15 text

൚༻ੑߴ͗͢ύλʔϯ 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ͱ͍͏໊લͰҙਤ͕఻Θ Δ͔ʁ

Slide 16

Slide 16 text

൚༻ੑߴ͗͢ύλʔϯ • scope1͕ͭ௕͘ͳΓɺmodelશମͷݟ௨͕͠ ѱ͍ • Ҿ਺͕ଟ͘ɺscope಺ʹifจ͕ࠞೖ͕ͪ͠ • ໋໊͕໎૸͠ɺҙਤ͕Θ͔Γʹ͍͘

Slide 17

Slide 17 text

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

Slide 18

Slide 18 text

ϕλʔͳํ਑ • scope͸γϯϓϧΛҙࣝ(ݟΕ͹Θ͔Δ) • scopeͷ੹຿͸ߜΓࠐΉ͜ͱ • ฒ΂׵͑Δ͜ͱɺeager loading͢Δ͜ͱ͸ݫີʹ͸ ҧ͏ • ෳࡶͳݕࡧɺฒ΂ସ͑ɺeager loading͸ Finder(Repository)ύλʔϯΈ͍ͨͳ΋ͷΛ࢖͓͏

Slide 19

Slide 19 text

RailΛ৳͹͢ϊ΢ϋ΢,ࢀߟࢿྉ • ActiveRecordσʔλॲཧΞϯνύλʔϯ @toshimaru_e ͞Μ https://speakerdeck.com/toshimaru/active-record-anti-patterns • DHHྲྀͷϧʔςΟϯάͰಘΒΕΔϝϦοτͱɾɾɾ kitchihike ͞ΜͷςοΫϒϩά https://tech.kitchhike.com/entry/2017/03/07/190739 • Ϩʔϧͷ৳͹͠ํ @netwillnet ͞Μ https://speakerdeck.com/willnet/rerufalseshen-basifang?slide=91

Slide 20

Slide 20 text

Thanks! ;͒ΖʔΈʔ @ngmt83