Save 37% off PRO during our Black Friday Sale! »

computed_modelの紹介 / Introducing computed_model (2)

computed_modelの紹介 / Introducing computed_model (2)

Ruby on RailsではDB上の生データから導出したデータを定義するためにモデルクラスに新たなメソッドを定義することがあります。しか、多数のレコードを効率よく読み出すためにpreloadを使うと、結局生データのありかを指定する必要があり抽象化が阻害されてしまいます。

computed_modelはこの問題を解決するために、モデルクラスでデータの依存関係を記述するDSLを提供します。この仕組みはActiveRecordなど特定のデータソースに依存せず、複数データソースにも対応しているため、特にマイクロサービス化によって分断されてしまったデータの再集約で効果を発揮します。

※Kaigi on Rails _2021_ new (LT会) で話したものとほぼ同一の内容です。 https://speakerdeck.com/qnighy/introducing-computed-model

Ba655e3712aaabfbca289fe136f85fe4?s=128

Masaki Hara

October 23, 2021
Tweet

Transcript

  1. ©2021 Wantedly, Inc. computed_model RailsϞσϧͷpreloadʹடংΛ༩͑Δ Oct 23, 2021 - Masaki

    Hara (@qnighy ) At Kaigi on Rails 2021 1
  2. ©2021 Wantedly, Inc. 8BOUFEMZʹ͓͚Δ3BJMT 2  ϞϊϦε3BJMT w 3BJMT7JFXΛͨ͘͞Μ͍࣋ͬͯΔ 

    3BJMTϚΠΫϩαʔϏε w ΄ͱΜͲ͸"1*0OMZ w ͦΕͧΕʹ%#Λ࣋ͭ w ͓ޓ͍͸)551 +40/PSH31$ QSPUPCVGͰ௨৴ ৄ͘͠͸ҎԼͷϖʔδ΋ࢀর https://www.wantedly.com/companies/wantedly/post_articles/193633 https://docs.wantedly.dev/
  3. ©2021 Wantedly, Inc. class User < ApplicationRecord def short_description current_job.then

    { |c| "#{c.company_name} #{c.position}" } end def current_job jobs.sort { ... }.find { ... } en d end DPNQVUFE@NPEFMͷಈػ Model method 3
  4. ©2021 Wantedly, Inc. class User < ApplicationRecord has_many :jobs end

    users = User.where(...).preload(:jobs).to_ a DPNQVUFE@NPEFMͷಈػ Preload 4
  5. ©2021 Wantedly, Inc. users = User.where(...).preload(:jobs).to_ a users.each do |user

    | sd = user.short_descriptio n .. . end DPNQVUFE@NPEFMͷಈػ Model method + preload 5
  6. ©2021 Wantedly, Inc. ੍໿  "DUJWF3FDPSEʹґଘ͠ͳ͍ w ଞϚΠΫϩαʔϏε͔Βऔಘ͢Δ৘ใ΋͋Δ w ෳ਺ιʔε͔Βͷ৘ใͷऔಘ΋ඞཁ

     ωετͨ͠QSFMPBE  7JFXʹඥ෇͔ͳ͍ w (SBQI2-ͳͲಛఆͷϓϩτίϧʹΑΒͣɺ൚༻తʹ࢖͍͍ͨ 6
  7. ©2021 Wantedly, Inc. class User dependency :current_job computed def short_description

    current_job.then { |c| "#{c.company_name} #{c.position}" } end dependency :jobs computed def current_job jobs.sort { ... }.find { ... } end end ղ๏ .PEFMʹґଘؔ܎Λॻ͘ એݴ͍ͯ͠ͳ͍ґଘؔ܎Λ࢖͏ͱ࣮ߦ࣌ΤϥʔʹͳΔ 7
  8. ©2021 Wantedly, Inc. class User include ComputedModel::Mode l dependency :current_job

    computed def short_description ... en d dependency :jobs computed def current_job ... end end ղ๏ .PEFMʹґଘؔ܎Λॻ͘ %FQFOEFODZ DPNQVUFE͸$PNQVUFE.PEFM.PEFM͔Βར༻Ͱ͖Δ 8
  9. ©2021 Wantedly, Inc. users = User.list(user_ids, [:short_description] ) users.each do

    |user | sd = user.short_descriptio n .. . end ղ๏ ཉ͍͠ϑΟʔϧυΛࢦఆͯ͠ϩʔυ ࢦఆ͍ͯ͠ͳ͍ϑΟʔϧυΛ௚઀࢖͏ͱ࣮ߦ࣌ΤϥʔʹͳΔ 9
  10. ©2021 Wantedly, Inc. class User define_primary_loader :raw_user do |subfields, ids:

    | RawUser.where(id: ids).preload(subfields).map do |raw_user | User.new(raw_user ) end end end ղ๏ σʔλιʔε΋ࣗ෼Ͱॻ͘ ͔ͩΒɺͲΜͳσʔλιʔεʹ΋ద߹͢Δ 10
  11. ©2021 Wantedly, Inc. class User define_primary_loader :raw_user { ... }

    define_loader :books, key: -> { id } do |user_ids, _subfields, ** | BookApi.list(user_id: user_ids).group_by(&:user_id ) end end ղ๏ ෳ਺σʔλιʔε ϚΠΫϩαʔϏε܈͔Β৘ใΛ͔͖ूΊΔͷ΋؆୯ 11
  12. ©2021 Wantedly, Inc. ࣾ಺ͷར༻ྫ  6TFSϞσϧ w Ϣʔβʔͷ৘ใʹؔ৺Λ࣋ͭαʔϏε͸ଟ͍ w ͦͷͨΊɺෳ਺ͷϚΠΫϩαʔϏε͔Β৘ใΛ

    
 ू໿͢Δඞཁ͕͠͹͠͹ੜ͡Δ  ݖݶ؅ཧ w "DUJWF3FDPSEͷϞσϧΛϥοϓͯ͠ɺ 
 ݟ͍͍ͯ৘ใ͚͕ͩϑΟϧλ͞ΕͨϞσϧΛ࡞Δ 12
  13. ©2021 Wantedly, Inc. ࣾ಺ͷར༻ྫ  γϦΞϥΠβ w ϞσϧͰ͸ͳ͘Ϗϡʔଆʹ࢖ͬͨྫ w 👉QCTFSJBMJ[FSHFN

    
 IUUQTHJUIVCDPNXBOUFEMZQCTFSJBMJ[FS 13
  14. ©2021 Wantedly, Inc. ·ͱΊ  1SFMPBE࣌ͷґଘղܾΛ࣮૷ͨ͠  "DUJWF3FDPSEҎ֎ʹ΋ରԠ  ෳ਺ϚΠΫϩαʔϏε͔Βͷ৘ใͷू໿ʹ΋࢖͑Δ

    https://github.com/wantedly/computed_model 14