ApplicationModel のある風景 / Rails with ApplicationModel

9936ddaf95702abb005b5b7b0dd2bfd6?s=47 hshimoyama
December 08, 2018

ApplicationModel のある風景 / Rails with ApplicationModel

Railsdm 2018 Day4 Nouvelle Vague section B [15:50-16:10 ]

Rails アプリケーションの成長に伴い、単一の ActiveRecord モデルにロジックを記述するのに不都合が出てきます。今回、それらの問題を『緩やかに』解消するための ApplicationModel 層の導入・活用方法と、既存のアプローチとの簡単な比較をご紹介出来ればと思います。

9936ddaf95702abb005b5b7b0dd2bfd6?s=128

hshimoyama

December 08, 2018
Tweet

Transcript

  1. ApplicationModel ͷ͋Δ෩ܠ Hiroyasu Shimoyama Web engineer at giftee inc. Twitter@_h_s_

  2. Overview • ApplicationModel ಋೖͷഎܠͱϞνϕʔγϣϯ • ApplicationModel ૚ͷ঺հ • طଘͷΞϓϩʔνͱͷൺֱ

  3. Rails ͷϓϩμΫτ։ൃ • ॳΊ͸γϯϓϧ • ঃʑʹෳࡶʹ • ෳࡶ͞ͱͲ͏޲͖߹͍͔ͬͯ͘ʁ

  4. ෳࡶ͞ • ආ͚ΒΕΔෳࡶ͞ͱɺආ͚ΒΕͳ͍ෳࡶ͞ • ݻ༗ͷෳࡶ͞ͱɺҰൠతͳෳࡶ͞ • ੔ཧ͞Εͨෳࡶ͞ͱɺແடংͳෳࡶ͞ • ༧ଌՄೳͳෳࡶ͞ͱɺ༧ଌࠔ೉ͳෳࡶ͞

  5. Rails ͷϨʔϧ • Rails ͷෳࡶ͞Λཧղ͢Δ͜ͱͰ • ආ͚ΒΕΔෳࡶ͞Λආ͚Δ • Ұൠతͳෳࡶ͞Λղܾ͢Δ •

    ෳࡶ͞Λ੔ཧͯ͠ίϯτϩʔϧ͢Δ • ༧ଌՄೳʹ͢Δ
  6. Rails MVC

  7. γϯϓϧͳੈք • 1 Model • 1 View • 1 Controller

  8. C M V

  9. routes ΍ DB table Λߟ͑Δ • 1 Model • 1

    DB table • 1 View • 1 Controller • 1 REST resource
  10. C M V T R

  11. গ͠ෳࡶͳੈք • ಉҰͷσʔλΛҟͳΔϦιʔεͱͯ͠ݟͤΔ • ҟͳΔ REST resource

  12. C M V T R C’ V’ R’

  13. ΋͏গ͠ෳࡶͳੈք • ϦιʔεΛҟͳΔίϯςΩετͰݟΔ • ؅ཧը໘ / API / etc. •

    namespace
  14. R C V R’ C’ V’ R C V Customer::

    M T Admin::
  15. ΋ͬͱෳࡶͳੈք • ݱ࣮͸ΑΓݫ͘͠ɺෳࡶʹͳΔҰํ • ݟͤํ͕૿͑Δ : Ϧιʔεͷ૿Ճ • ༻్͕૿͑Δ :

    ίϯςΩετͷ૿Ճ
  16. R Customer:: M T C R’ C’ R’’ C’’ R’’’

    C’’’ R C R’ C’ R’’ C’’ R C R C Api:: Admin:: Etc::
  17. ߋʹෳࡶͳੈք • ͦΕͧΕ͕୲͏੹຿΋૿Ճ͍ͯ͘͠ • ௨஌ / ඇಉظॲཧ / ֎෦APIґଘ /

    ঢ়ଶ؅ཧ / etc. • Model ͷෳࡶ͞ ++
  18. R Customer:: M T C R’ C’ R’’ C’’ R’’’

    C’’’ R C R’ C’ R’’ C’’ R C R C Api:: Admin:: Etc::
  19. ୯ҰͷϞσϧʹ ෳࡶ͕͞ूத

  20. ୯ҰϞσϧͷ໰୊ • ѻ͍͍ͨσʔλ → 1 Table (ͱͦͷؔ࿈) → 1 Model

    • σʔλΛѻ͏શͯͷෳࡶ͞ → 1 Model
  21. R Customer:: M T C R’ C’ R’’ C’’ R’’’

    C’’’ R C R’ C’ R’’ C’’ R C R C Api:: Admin:: Etc::
  22. ղܾͷΞϓϩʔν • ϞσϧΛ෼ׂ͢Δ • ϩδοΫΛॻ͘ͷʹઐ೦͢ΔͨΊͷϞσϧ • Rails ͷϨʔϧʹ͓͍ͯ༧ଌՄೳͳ໊শ REST resource

    Controller View Model DB Table /users UsersController users/* User users /admin/users Admin::
 UsersController admin/users/* User
 →Admin::User users
  23. R Customer:: M T C R’ C’ R’’ C’’ R’’’

    C’’’ R C R’ C’ R’’ C’’ R C R C Api:: Admin:: Etc:: Customer::M Customer::M’ Customer::M’’ Customer::M’’’ Api::M Api::M’ Api::M’’ Admin::M Etc::M
  24. Ͳ͏ϨʔϧʹࡌͤΔ͔ • ʰςʔϒϧʹඥ෇͔ͳ͍Ϟσϧ૚ʱΛۃྗϨʔϧ͔Β֎Ε ͳ͍Α͏ʹఆٛ͠ɺͦΕΛཧղ͢Δ͜ͱͰ • ආ͚ΒΕΔෳࡶ͞Λආ͚Δ • Ұൠతͳෳࡶ͞Λղܾ͢Δ • ෳࡶ͞Λ੔ཧͯ͠ίϯτϩʔϧ͢Δ

    • ༧ଌՄೳʹ͢Δ
  25. ApplicationModel

  26. • Controller ͕ Model ʹظ଴͢Δڞ௨ͷৼΔ෣͍Λදݱ͢ Δ • ςʔϒϧʹඥ෇͍ͨϞσϧ → ApplicationRecord

    • ςʔϒϧʹඥ෇͔ͳ͍Ϟσϧ → ApplicationModel ApplicationModel
  27. • ApplicationRecord Model Λѻ͏Α͏ʹѻ͍͍ͨ • Attributes • όϦσʔγϣϯ • ؔ࿈ͷදݱ

    • etc. ApplicationModel ʹ
 ظ଴͢Δػೳͷྫ
  28. • ActiveModel ϕʔε • gem (virtus, dry-rb, reform) ϕʔε ApplicationModel

    ͷ࣮૷
  29. • ◦ : Rails ͷػೳͰ࣮ݱग़དྷΔ • × : ActiveModel::Attribute ͕

    Internal API • × : ػೳతʹ෺଍Γͳ͍͕࣌͋Δ (ؔ࿈ (Nesting) ౳) • : ࣗલ࣮૷ → ݻ༗ͷෳࡶ͞ͷݩ ActiveModel ϕʔε class ApplicationModel include ActiveModel::Model include ActiveModel::Attributes end
  30. • ◦ : ࡉ͔͘ΧελϚΠζग़དྷΔ • ◦ : ػೳతʹදݱग़དྷΔ෯͕޿͍ • ×

    : ֤छ gem ͷ஌͕ࣝඞཁ • × : ApplicationRecord ͱه๏͕ҟͳΔ • attribute/property(reform), validation/required(dry-rb) gem (dry-rb, reform) ϕʔε
  31. • ௚ۙͷϓϩδΣΫτ͸ ActiveModel ϕʔεΛબ୒ • ؔ࿈ = Nesting ͕ແ͍ͷ͕ݫ͍͠ •

    ࣗલ࣮૷ͯ͠͠·ͬͨ෦෼͕ෛ࠴Խͯͦ͠͏ • ݱঢ়ͲΕ΋Ұ௕Ұ୹͋Γͦ͏ • dry-rb : ʰͲͷ gem Λ૊Έ߹Θ͔ͤͨʱ͕ෳࡶ • reform : Form ͱ͍͏໊෇͚ʹҾͬுΒΕΔ ͲΕΛબͿ΂͖͔ʁ
  32. • ෼ׂͨ͠ Model ΛͲ͏ DRY ʹอ͔ͭʁ • όϦσʔγϣϯ • ڞ௨ػೳ

    • ApplicationModel Model ͷ attributes ͱ ApplicationRecord Model ͷ attributes ͷಉظ TIPS
  33. • ڞ௨ͷόϦσʔγϣϯϧʔϧ • ApplicationRecord ͷ Model ʹॻ͘ • ಛఆ༻్ͷΑΓݫີͳόϦσʔγϣϯ •

    ApplicationModel ͷ Model ʹॻ͘ • ͦΕΒΛڞ௨Խ͢Δͱ͖͸ CustomValidator DRY : όϦσʔγϣϯ
  34. • ҎԼͷͲͪΒ͔ • Concerns • ApplicationModel Model • ΦϓγϣφϧͳৼΔ෣͍ͷ࣌͸લऀɺ୯Ұػೳͱͯ͠੒ཱ ͢Δ৔߹͸ޙऀΛબ୒͢Δ͜ͱ͕ଟ͍

    DRY : ڞ௨ػೳ
  35. • ApplicationModel Model ͱͯ͠ड͚औΓɺvalidation ʹ໰ ୊͕ແ͔ͬͨ࣌ɺActiveRecord Model ʹӬଓԽΛґཔ͢ Δ •

    Ͳͷ attribute ͕Ͳͷ attribute ʹରԠ͍ͯ͠Δͷ͔ʁ • ͲͷλΠϛϯάͰ஋Λίϐʔ͢Δͷ͔ʁ • ͦΕΒΛࣗಈԽ͢Δػೳ͸༻ҙ͞Ε͍ͯΔͷ͔ʁ Sync : attributes
  36. • ActiveModel ϕʔεͷ ApplicationModel Ͱ͸ࣗલ࣮૷ Sync : attributes class Admin::User

    < ApplicationModel associate :user, User, default: -> { User.new } attribute :name, :string, for: :user validates_associated :user def save sync_attributes return false unless valid? user.save end end
  37. Sync : attributes class Admin::UsersController < Admin::ApplicationController def new @admin_user

    = Admin::User.new end def create @admin_user = Admin::User.new(admin_user_create_params) if @admin_user.save redirect_to @admin_user else render :new end end def edit @admin_user = Admin::User.new(user: ::User.find(params[:id])) end def update @admin_user = Admin::User.new(admin_user_update_params) if @admin_user.save redirect_to @admin_user else render :edit end end # … end
  38. • Ϩʔϧ͔Β͋·Γ֎Ε͍ͯͳ͍ (ͱࢥ͏) • σʔλ͸୯Ұͷ ApplicationRecord Model Λܦ༝͢Δ • ActiveRecord::Attributes

    ͰߦͬͯΔ cast ౳ͷॲཧ͕ ͋Ε͹ͦ͜ʹॻ͘ • ໊෇͚౳Ͱ͋·ΓࠔΒͳ͍ ApplicationModel ͷ
 Կ͕خ͍͠ͷ͔
  39. طଘͷΞϓϩʔνͱͷൺֱ • ApplicationRecord Model Λ෼ׂ͢Δ • PORO (Plane Old Ruby

    Object) • Service / Form • Rails MVC Λ֦ு͢Δ
  40. Rails MVC Model ૚ͰରԠ • ApplicationRecord Model Λ෼ׂ͢Δ • ActiveRecordͷϞσϧ͕1ͭͩͱͭΒ͍(@hanachin_)


    https://qiita.com/hanachin_/items/ba1dd93905567d88145c • PORO (Pure Old Ruby Object) • RailsͷଠͬͨϞσϧΛμΠΤοτͤ͞Δํ๏ʹ͍ͭ ͯ (@willnet)
 https://tech.medpeer.co.jp/entry/2017/11/08/120000
  41. ApplicationRecord Model Λ෼ׂ͢Δ • ActiveRecordͷϞσϧ͕1ͭͩͱͭΒ͍(@hanachin_)
 https://qiita.com/hanachin_/items/ba1dd93905567d88145c • ϒϩάهࣄͰݕ౼͞Ε͍ͯΔ௨Γɺඇৗʹ্ख͘work ͢ Δ

    • ApplicationRecord Model ෼ׂͰ΋ྑ͍ͱࢥ͏ • ʰActiveRecordҎ֎ͷ૚ͭ͘Δͱҙ֎ͱ໘౗ʱͰ΋ ݴٴ͞Ε͍ͯΔ௨Γɺ͔֬ʹ໘౗
  42. ApplicationRecord Model Λ෼ׂ͢Δ • ApplicationModel ͷར఺ • DB migration ࣌ʹ໘౗͕গͳ͍

    (ignore_columns) • ActiveRecord::AssociationTypeMismatch ղফύζϧ ʹͳΒͳ͍ • σʔλӬଓԽՕॴΛߜΕΔ
  43. PORO • RailsͷଠͬͨϞσϧΛμΠΤοτͤ͞Δํ๏ʹ͍ͭͯ (@willnet)
 https://tech.medpeer.co.jp/entry/2017/11/08/120000 • ApplicationModel ͸ better PORO

    • Ϟσϧ૚ʹ͋ΔΫϥε͸ ApplicationRecord ΋͘͠͸ ApplicationModel Λܧঝͨ͠ΫϥεͷΈɺͱ͍͏੤໿ʹ ΑΓɺϞσϧ૚ʹظ଴͢Δڞ௨ͷৼΔ෣͍Λఆ͍ٛͯ͠Δ • PORO ͷํ͕ࣗ༝ͳར఺΋͋ΔͷͰ͓޷ΈͰ
  44. Service / Form • Service / Form ͷྑ͍ͱ͜Ζ • ApplicationModel

    ͔Βߋʹ෼ׂ͞ΕɺϑΥʔΧε͢ Δ੹຿͕গͳ͍ • ੈؒతʹ͋Δఔ౓ೝ஌͞Ε͍ͯͯɺ֓೦͕ʢൺֱతʣ ఻ΘΓ΍͍͢ • (ҙ֎ͱ GraphQL mutation ͱ૬ੑ͕ྑ͍ͱࢥ͏)
  45. Service / Form • Service / Form ͷͭΒ͍ͱ͜Ζ • ৽͍֓͠೦ͷಋೖ͕ඞཁͰϨʔϧ͔Βएׯ֎ΕΔ

    • ໊લ෇͚΍ݺͼग़͠खॱͷηΦϦʔཱ͓֬ͯ͠Βͣɺ ਪଌ͕೉͍͠ • ApplicationRecord Model ෼ׂͷ߲Ͱ৮Εͨ ApplicationModel ͷ໘౗͞Λ Service / Form ΋౿ऻ ͍ͯ͠Δ
  46. Rails MVC Λ֦ு • ઃܭख๏͸ड͚ೖΕΒΕ͍ͯΔ͕ɺRails Ͱͷ࣮ݱํ๏͕ ཱ֬͞Ε͍ͯͳ͍΋ͷ • Clean Architecture

    • Layered Architecture • Rails Ͱͷ࣮ݱํ๏ཱ͕֬͞Ε͍ͯΔ΋ͷ • Trailblazer
  47. Rails MVC Λ֦ு • ݸਓతʹ͸ಋೖʹ৻ॏ • ͜ΕΒΛಋೖ͢ΔΤϯδχΞ͸શମΛʰઃܭ͢Δʱ෦෼ʹ ڧΈΛ࣋ͬͨਓ͕ଟ͘ɺඞͣ͠΋ӡ༻Λಘҙͱ͍ͯ͠ͳ͍ • Ҿ͖ܧ͙ϝϯόʔ͕ಋೖ͞Εͨઃܭख๏ʹशख़͍ͯ͠ͳ͍

    Մೳੑͷ΄͏͕ߴ͍ • େن໛։ൃͰϝϦοτΛे෼ʹڗडग़དྷΔ͔ɺઃܭख๏ʹ͍ͭͯ ਂ͘शख़ͨ͠ϝϯόʔΛἧ͑ଓ͚ΒΕΔͷͰ͋Ε͹… • ͱʹ͔͘ɺϨʔϧ͔Βେ͖͘ҳ୤͢ΔͷͰಋೖʹʰ֮ޛʱ͕ඞཁ
  48. ApplicationModel 
 ΛબͿ΂͖͔ʁ • ٻΊΒΕΔ੹຿෼ׂͷཻ౓ͰબΜͰྑͦ͞͏ • 1 ApplicationRecord • N

    ApplicationRecord • N ApplicationModel + 1 ApplicationRecord • N Forms + N’ Services + 1 ApplicationRecord • Trailblazer, Clean Architecture, Layered Architecture
  49. ·ͱΊ • ApplicationModel Λಋೖ͢Δͱɺscaffold Ͱ࡞ͬͨϞσϧ ͷΑ͏ʹϩδοΫهड़૚Λಋೖग़དྷ·͢ • طଘͷΞϓϩʔνʹൺ΂ͯར఺ܽ఺͸͋Δ͚ΕͲɺϨʔϧ ʹԊͬͨ։ൃ͸͠΍͍͢ͱࢥ͍·͢ •

    બ୒ࢶͷҰͭͱͯ͠ࢹ໺ʹ͓͍ͯ௖͚ͨΒ޾͍Ͱ͢
  50. “Arigato!”