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

Railsでモデルのステータスを扱うベタープラクティス/Better practice to handle state on Rails

A1c45e2d61b0d9a7af26c52244be6d93?s=47 ngmt
February 07, 2019

Railsでモデルのステータスを扱うベタープラクティス/Better practice to handle state on Rails

A1c45e2d61b0d9a7af26c52244be6d93?s=128

ngmt

February 07, 2019
Tweet

More Decks by ngmt

Other Decks in Technology

Transcript

  1. RailsͰ ϞσϧͷεςʔλεΛѻ͏ ϕλʔϓϥΫςΟε

  2. ࢲ(@ngmt83)ʹ͍ͭͯ • ट౎ݍ͕ۤख͗͢Δ΍΂ʔ΍ͭ • ϑϧελοΫΤϯδχΞ(༧ఆ) <- twitter portfolio ->

  3. ͍͖ͳΓͰ͕͢ Ϟσϧͷεςʔλε Ͱࠔͬͨ͜ͱ͋Γ·ͤΜ͔ʁ ͋Γ·͢ΑͶʁ

  4. ྫ • SNSͷΞΧ΢ϯτ ༑ୡ, ༑ୡਃ੥த, ༑ୡղআࡁ, ϛϡʔτ, ϒϩοΫ • ఆ੍ֹαʔϏεͷϓϥϯ

    Free, Basic, Pro, ٳࢭத, ΞΧ΢ϯτ࡟আ, ͓ࢼ͠༻ϓϥϯ • ܾࡁ ϦΫΤετத, ঝೝࡁ, ࢧ෷͍଴ͪ, ܾࡁࣦഊ, Ωϟϯηϧࡁ, ෦෼ฦۚ
  5. ࠔͬͨྫ • DBΛݟͯ΋ͲΜͳঢ়ଶ͔ͺͬͱΘ͔Γʹ͍͘ɺ෼ੳͮ͠Β͍ • ಛఆϝϯόʔ͔͠εςʔλε൑ఆ͕Ͱ͖ͳ͍ • ฉ͍ͨ͜ͱͷͳ͍εςʔλε͕ੜ·Ε͍ͯΔ • ໓ଟʹ࢖༻͞Εͳ͍εςʔλε͕࢒͍ͬͯΔ •

    ഉଞతͳ͸ͣͷεςʔλεཱ͕྆͢Δ • εςʔλε൑ఆͷͨΊʹύϑΥʔϚϯε͕མͪΔ • etc
  6. ݪҼ • εςʔλεʹؔ͢Δઃܭڞ༗ෆ଍ or ߋ৽࿙Ε • εςʔλεछྨͷ૿Խɺεςʔλεؔ࿈৚݅ͷෳࡶԽ - ૝ఆ֎ͷεςʔλε -

    ͦͷ৔͠ͷ͗తʹ҆қʹ૿΍ͨ͠εςʔλε - εςʔλεA->B͸ભҠՄೳ͕ͩɺA->C͸ભҠͰ͖ͳ͍ - Ϟσϧx͕ଘࡏ͠ɺϞσϧy͕ଘࡏ͠ͳ͍৔߹͸εςʔλεD • ࠷ॳظʹա౓ʹॊೈੑΛ࣋ͬͨઃܭΛ͢Δ
  7. ݁࿦͔Β

  8. ΠϯΫϦϝϯλϧʹվળ͠Α͏ 0. ঢ়ଶભҠਤΛॻ͘ 1. ਖ਼نԽ͞ΕͨDB͔Βεςʔλε৘ใΛಡΈ औΔ(εςʔλε৘ใΛӬଓԽ͠ͳ͍) 2. εςʔλε৘ใΛDB্ʹӬଓԽ͢Δ

  9. ྫ • SNSͷΞΧ΢ϯτ(UserϞσϧ)ʹ͍ͭͯߟ͑Δ • ొ࿥ɺਖ਼ࣜొ࿥ɺୀձɺBAN͕͋Δ

  10. ঢ়ଶભҠਤ State Machine Diagram Λॻ͘

  11. ঢ়ଶભҠਤΛॻ͘

  12. PlantUMLͩͱϨϏϡ͠΍͍͢ @startuml{super-simple-state- machine.png} title Userঢ়ଶભҠਤ0 [*] --> registered : ొ࿥͢Δ

    registered --> active : ਖ਼ࣜʹొ ࿥͢Δ active --> banned : BAN͞ΕΔ active --> Inactive : ୀձ͢Δ @enduml .puml
  13. ਖ਼نԽ͞ΕͨDB͔Βεςʔλ ε৘ใΛಡΈऔΔ

  14. Ϋϥεਤ (schema.rb͔Βࣗಈੜ੒΋Ͱ͖·͢) ※ΠϕϯτܥΤϯςΟςΟΛ࿙Β͞ͳ͍

  15. User.rb class User < ApplicationRecord has_one :activation, class_name: 'UserActivation' has_one

    :deactivation, class_name: 'UserDeactivation' has_one :ban, class_name: 'UserBan' def status return 'active' if active? return 'banned' if banned? return 'inactive' if inactive? return 'registered' end def registered? return false if banned? || inactive? || active? true end def active? return false if banned? || inactive? return false unless activation.present? true end def banned? ban.present? end def inactive? deactivation.present? end def activate! raise StandardError unless registered? create_activation! end def ban! raise StandardError unless active? create_ban! end def deactivate! raise StandardError unless active? create_deactivation! end end user.rb user.rbଓ͖
  16. ΞΧ΢ϯτౚ݁ػೳ Λ ௥Ճ࣮૷͍ͨ͠ ͔͠͠ εςʔλε͕ෳࡶԽɾɾɾ

  17. εςʔλε৘ใΛ DB্ʹӬଓԽ͢Δ

  18. Ϋϥεਤ (ΞϓϦ͔Βࣗಈੜ੒΋Ͱ͖·͢)

  19. ঢ়ଶભҠਤΛߋ৽ @startuml{state.png} title Userঢ়ଶભҠਤ [*] --> registered registered --> active

    : ਖ਼ࣜʹొ࿥͢Δ active --> suspended : ౚ݁͞ΕΔ suspended --> active : ౚ݁ղআ͞ΕΔ suspended --> banned : BAN͞ΕΔ suspended --> Inactive : ୀձ͢Δ active --> banned : BAN͞ΕΔ active --> Inactive : ୀձ͢Δ @enduml puml
  20. ঢ়ଶભҠਤΛߋ৽

  21. ෳࡶͳঢ়ଶભҠʹ͸ AASM ͱ͍͏gemΛ͓͢͢Ί͠·͢

  22. AASMʹΑΔঢ়ଶભҠ aasm do state :registered, :initial => true state :active,

    :suspended, :banned, :inactive event :activate do transitions from: :registered, to: :active end event :suspend do transitions from: :active, to: :suspended end event :unsuspend do transitions from: :suspended, to: :active end event :ban do transitions from: [:active, :suspended], to: :banned end event :deactivate do transitions from: [:active, :suspended], to: :inactive end end user.rb಺ͷaasm࣮૷෦෼(؆қίʔυ)
  23. AASMʹෳࡶͳঢ়ଶભҠ has_many :suspensions, class_name: 'UserSuspension' has_one :active_suspension, lambda { where(removed_at:

    nil) }, class_name: ‘UserSuspension' aasm do … event :suspend do transitions from: :active, to: :suspended, guard: :without_active_suspension? after do suspensions.create! end end … end def without_active_suspension? return false if active_suspension true end user.rbͷౚ࣮݁૷෦෼
  24. ऄ଍ • ਖ਼نԽͤͣʹΰϦԡ͢ύλʔϯ΋͋Δ

  25. ·ͱΊ • εςʔλε؅ཧ͸ΠϯΫϦϝϯλϧʹվળ͠Α͏ - ʮεςʔλεʹؔ͢Δઃܭڞ༗ෆ଍ or ߋ৽࿙Εʯରࡦ →PlantUMLͱϨϏϡͰઃܭڞ༗ɾߋ৽Λ࿙Β͞ͳ͍ - ʮεςʔλεछྨͷ૿Խɺεςʔλεؔ࿈৚݅ͷෳࡶԽʯରࡦ

    →AASM gemͰεςʔλε؅ཧɾ࣮૷Λ؆୯ʹ - ʮ࠷ॳظʹա౓ͳॊೈੑΛ࣋ͬͨઃܭΛ͢Δʯରࡦ →࠷ॳ͸খ࢝͘͞ΊΔɻDBઃܭ͕ਖ਼نԽ͞Ε͍ͯΕ͹͍͍ͩͨޙͰͲ ͏ʹ͔Ͱ͖Δ