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

実践 Rails アソシエーションリファクタリング / Rails association refactoring in practice

実践 Rails アソシエーションリファクタリング / Rails association refactoring in practice

Kei Shiratsuchi

October 22, 2022
Tweet

More Decks by Kei Shiratsuchi

Other Decks in Technology

Transcript

  1. Πϯτϩ • Day 1 ͷ @pndcat ͞ΜʹΑΔʰ৿ཏສ৅ʹʮ͍͍Ͷʯ͢ΔͨΊͷ σʔλߏ଄ ʱͷɺٯํ޲ͷϦϑΝΫλϦϯάͷ࿩Λ͠·͢ •

    ϙϦϞʔϑΟοΫؔ࿈Λதؒςʔϒϧ΁ • ͲͪΒ΋ɺཧ༝͕͋ͬͯҙຯ͕͋Δɺͱ͍͏͜ͱΛ࣋ͬͯ ؼ͍͚ͬͯͨͩΕ͹ 🙏 • ͲͪΒ΋࠾༻͍͍ͯͨͩͨ͠ Kaigi on Rails νʔϜ͍͢͝ 👏
  2. ࣗݾ঺հ • ന౔ɹܛʢγϥπνɹέΠʣ • : kei-s, : @kei_s • ANDPAD

    גࣜձࣾ Tech Lead • ॳΊͯ rails new ͔ͯ͠Β 15 ೥͘Β͍ • ࠓ೔͸ Kaigi on Rails ͷୗࣇαϙʔτΛར༻ͤͯ͞΋Β͍ͬͯ·͢ • ͱͯ΋ྑ͍औΓ૊ΈͰײँ͍ͯ͠·͢ʂ
  3. લఏ • ANDPAD : ݐஙɺݐઃۀ޲͚ͷ SaaS • த৺ͱͳΔҰͭͷ Rails ΞϓϦͰɺෳ਺ͷۀ຿υϝΠϯͷόο

    ΫΤϯυΛఏڙ͍ͯ͠Δ • ࢪ޻؅ཧɺݕࠪɺνϟοτɺetc… • ͦΕͧΕͷυϝΠϯʹ։ൃνʔϜ͕͋Δ • ͦΕΒͷνʔϜ͕Ұͭͷ Rails ΞϓϦʹରͯ͠ػೳ։ൃͯ͠ ͍Δ
  4. എܠ • ෳ਺ͷυϝΠϯͷػೳ͕૬৐Γ͍ͯ͠ΔͨΊɺRails ΞϓϦ͸͔ͳΓେن໛ʹͳͬ ͍ͯΔ • Day 1 ͷ makicamel

    ͞ΜͷൃදΛࢀর͍ͩ͘͞ • ͜ͷ Rails ΞϓϦͰɺϙϦϞʔϑΟοΫؔ࿈͕ଟ༻͞Ε͍ͯΔ • ಛʹʮࣸਅʯ΍ʮࢿྉʯͳͲɺ͍ΘΏΔετοΫσʔλͷؔ࿈෇͚ʹ༻͍Β Ε͍ͯΔ • ͜ΕΒͷσʔλ͸ɺυϝΠϯΛލ͍Ͱར༻͞Ε͍ͯΔ • ͋ΔυϝΠϯͰ࡞੒͞ΕͨσʔλΛɺผͷυϝΠϯ͔ΒࢀরͰ͖Δ • ྫɿࢪ޻؅ཧͰΞοϓϩʔυͨࣸ͠ਅΛɺνϟοτʹషΓ෇͚Δ
  5. ϙϦϞʔϑΟοΫؔ࿈ͱ͸ • ҰͭͷϞσϧΛෳ਺ͷϞσϧʹඥ͚ͮΔ • *_type ΧϥϜʹ਌ϞσϧͷΫϥε໊Λ อଘ͢Δ • ར఺: ͋ΒΏΔϞσϧʹඥ͚ͮΔ͜ͱ͕

    Ͱ͖Δ • ઃܭ࣌ʹଘࡏ͠ͳ͔ͬͨϞσϧͱ΋ ඥ͚ͮΒΕΔ • ܽ఺: DBͰ֎෦ΩʔΛઃఆͰ͖ͳ͍ class Picture < ApplicationRecord belongs_to :imageable, polymorphic: true end class Employee < ApplicationRecord has_many :pictures, as: :imageable end class Product < ApplicationRecord has_many :pictures, as: :imageable end @employee.pictures # = > [#<Picture: . . >, . . ] @product.pictures # = > [#<Picture: . . >, . . ]
  6. ਅͷ՝୊ • কདྷతʹɺେن໛RailsΞϓϦΛ 
 υϝΠϯ͝ͱʹղମ͍͖͍ͯͨ͠ • ۩ମతͳಓے͸ To Be Determined

    • υϝΠϯΛލ͍Ͱ࢖ΘΕΔσʔλ ͷѻ͍͸ඞͣ՝୊ʹͳΔ • શ༰͕೺ѲͰ͖ͳ͍ෳࡶͳ࣮૷Λ ղফ͢Δඞཁ͕͋Δ Rails ΞϓϦ ࢪ޻؅ཧ νϟοτ ࣸਅ Ϟσϧ Ϟσϧ ϚΠΫϩαʔϏεʁ ϞδϡϥϞϊϦεʁ
  7. ϦϑΝΫλϦϯάํ਑ • ϙϦϞʔϑΟοΫؔ࿈Λɺதؒ ςʔϒϧʹΑΔؔ࿈෇͚ʹஔ͖׵ ͑Δ • ؔ࿈෇͚Λ໌ࣔͰ͖Δ • ॻ੶ʮSQLΞϯνύλʔϯʯͰ΋ ঺հ͞Ε͍ͯΔख๏

    class Photo < ApplicationRecord has_many :message_photos has_many :messages, through: :message_photos end class MessagePhoto < ApplicationRecord belongs_to :message belongs_to :photo end class Message < ApplicationRecord has_many :message_photos has_many :photos, through: :message_photos end
  8. ҠߦͷྲྀΕ • 4ճͷϦϦʔε🚀ɺ2ճͷσʔλमਖ਼📝Λߦ͏ 1. 🚀 ҠߦઌϞσϧ࡞੒ɺچˠ৽ͷಉ࣌ॻ͖ࠐΈ 2. 📝 طଘσʔλΛ৽ΞιγΤʔγϣϯʹొ࿥ 3.

    🚀 ৽ΞιγΤʔγϣϯʹஔ͖׵͑ɺ৽ˠچͷಉ࣌ॻ͖ࠐΈ 4. 🚀 ൈ͚࿙Εݕ஌ 5. 🚀 ࢓্͛ 6. 📝 چσʔλΛ࡟আ
  9. 1. 🚀 ҠߦઌϞσϧ࡞੒ɺچˠ৽ͷಉ࣌ॻ͖ࠐΈ • ҠߦઌͱͳΔதؒςʔϒϧΛ࡞੒͢Δ • ৽ΞιγΤʔγϣϯΛɺچΞιγΤʔγϣϯͱ͸ผ໊Ͱੜ΍͢ • after_create ίʔϧόοΫͰɺچΞιγΤʔγϣϯ͕࡞੒͞ΕͨΒ৽ΞιγΤʔ

    γϣϯΛಉ࣌ʹ࡞੒͢Δ • ඞཁʹΑͬͯɺߋ৽ɾ࡟আ͞ΕΔ৔߹΋ରԠ • 👉 ͜Ε͔Β௥Ճ͞ΕΔσʔλ͸৽چͰಉظ͞ΕΔ class Message < ApplicationRecord has_many :photos, as: :imageable has_many :message_photos has_many :renewed_photos, through: :message_photos, source: :photo end class Photo < ApplicationRecord belongs_to :imageable, polymorphic: true has_many :message_photos has_many :messages, through: :message_photos after_create :create_message_photos!, if: - > { imageable.is_a?(Message) } def create_message_photos! message_photos.create!(message: imageable) end end
  10. 3. 🚀 ৽ΞιγΤʔγϣϯʹஔ͖׵͑ɺ৽ˠچͷಉ࣌ॻ͖ࠐΈ • ผ໊Ͱ࡞੒ͨ͠৽ΞιγΤʔγϣϯΛར༻͢ΔΑ͏मਖ਼͢Δ • ৽ΞιγΤʔγϣϯΛ࢖ͬͯɺγϯϓϧͳ࣮૷Λ͢Δ • ࡞੒ɾߋ৽Օॴ͸ϑΟʔνϟʔτάϧͰ੾Γ໭ͤΔΑ͏ʹ͢Δ •

    ৽ˠچͷಉ࣌ॻ͖ࠐΈΛ࣮૷͢Δ • ࡞੒࣌ʹ *_type ͱ *_id Λద੾ʹຒΊΔ • چˠ৽ͷಉ࣌ॻ͖ࠐΈ͸ఀࢭͤͣҡ࣋͢Δ • ஔ͖׵͑ʹൈ͚͕͋ͬͨ৔߹΍੾Γ໭ͨ͠͠৔߹ʹ໰୊͕ى͖ͳ͍Α͏ʹ • 👉 ·ͩɺશͯͷσʔλ͕৽چͰಉظ͞ΕΔ
  11. 4. 🚀 ൈ͚࿙Εݕ஌ • چΞιγΤʔγϣϯ͕ར༻͞ΕͨΒɺϩάΛग़ྗͤ͞Δ • extend: Φϓγϣϯʹϩά༻ϞδϡʔϧΛ౉͠ɺϞδϡʔϧͷ self.extended ͕ൃ

    Րͨ͠ΒɺͲ͔͜ͰΠϯελϯεԽ͞Εͨ͸ͣ • ϩάʹ backtrace Λग़͠ɺͲ͔͜Βݺ͹Ε͔ͨΛௐࠪ͢Δ • 👉 ϓϩμΫγϣϯͰϩά͕ग़Δ͔Ұఆظ༷ؒࢠΛݟΔ class Message < ApplicationRecord has_many :photos, as: :imageable, extend: LoggingLeakage end module LoggingLeakage def self.extended(obj) # ผʑͷ obj Ͱ3ճݺͼग़͞ΕΔͨΊɺҰ౓͚࣮ͩߦ͞ΕΔΑ͏ʹ͢Δ return if obj.class.to_s ! = 'Photo : : ActiveRecord_Associations_CollectionProxy' backtrace = caller.grep(/ # { Regexp.escape(Rails.root.to_s)}/) leakage_logger.info "Replace leakage detected. # { backtrace}" end end
  12. ઐ೚νʔϜ • ϦΞʔΩςΫςΟϯάνʔϜͱ໋໊͞Ε ͨɺυϝΠϯΛԣஅ͢ΔՕॴͷվળΛߦ ͏νʔϜ • طଘͷ࢓૊ΈͷͭΒ͍෦෼Λղফ͠ɺ ͓खຊͱͳΔΑ͏ͳ΋ͷΛ࡞Δ • ։ൃνʔϜશମͰɺվળ׆ಈΛܧଓ͠

    ͯ΍Δͧɺͱ͍͏จԽΛৢ੒͍ͨ͠ • ·ͣ͸σʔλϞσϧपΓͷΞιγΤʔ γϣϯվળʹணख Rails ΞϓϦ ࢪ޻؅ཧ νϟοτ ࣸਅ Ϟσϧ Ϟσϧ
  13. εύΠΫίʔυͷॏཁੑ • ࣮ࡍʹҠߦΛ࢝ΊΔલʹɺҠߦεςοϓͷશͯΛ࣮૷ͯ͠ΈΔ • ࣮૷͸ࣺͯͯ΋ྑ͍ • ׬੒·Ͱͷෆ֬ఆཁૉΛશͯ௵͓ͯ͘͠ • ໎͏ͱ͜ΖΛϖΞϓϩͳͲͰղܾ͢Δ •

    ʮௐࠪʯͱʮ࣮ࢪʯͰϑΣʔζΛ෼͚Δ • εύΠΫ࡞ۀͷݟੵΓ͸೉͍͕͠ɺ࣮ࡍͷҠߦ࡞ۀ͸ݟੵΓ͕͠ ΍͍͢ • ʮ࣮ࢪʯظؒதʹɺผՕॴͷʮௐࠪʯΛฒߦͰ͖Δ
  14. ࡉ͔ͳ Tipsʢ࣌ؒతʹׂѪʣ • ΞιγΤʔγϣϯʹ dependent: :destroy ͕͋Δ৔߹ɺಈ࡞͕มΘΔ • ϙϦϞʔϑΟοΫؔ࿈Ͱ͸ࢠϞσϧ΋࡟আ͞ΕΔ͕ɺதؒςʔϒϧؔ࿈Ͱ ͸ɺதؒཁૉϞσϧͷΈ࡟আ͞ΕΔ

    • callback ͳͲͰࢠϞσϧ΋࡟আ͢ΔΑ͏ʹ͢Δ • چˠ৽ͱ৽ˠچͷಉ࣌ॻ͖ࠐΈ͕྆ํଘࡏ͢ΔλΠϛϯά͕͋ΔͨΊɺೋॏʹ ൃՐ͢ΔͷΛճආ͢Δ • อଘ࣌ʹ :skip_double_write ͷΑ͏ͳ attribute Λੜ΍੍ͯ͠ޚ͢Δ • ൈ͚࿙Εݕ஌ͷϩά͸ಉ͡ՕॴͰଟྔʹग़ΔՄೳੑ͕͋ΔͨΊɺ1ϦΫΤετͰ ॏෳ͢ΔϩάΛ uniq ͢ΔػߏΛ࢓ࠐΉ
  15. ·ͱΊ • σʔλϞσϧઃܭΛஔ͖׵͑Δͷ͸݁ߏେม • ՄೳͳݶΓϦϦʔεલʹݕ౼͠Α͏…! • ͱ͸͍͑ɺ౰ॳ૝ఆͱมΘΔ͜ͱ͸͋ΓಘΔ • ෳࡶͰྑ͘ͳ͍෦෼͸ɺ์ஔ͍ͯ͠Δͱ૿͑Δ •

    ෳࡶͰ೉͍͔͠Βͦ͜ɺલྫΛ౿ऻͯ͠͠·͏ • ϦϑΝΫλϦϯάʹΑͬͯʮՁ஋Λఏڙ͠ଓ͚Δʯʹد༩͢Δ • ʮ͠ଓ͚ΔʯͨΊʹɺ෼͔Γ΍͘͢ɺखΛೖΕ΍͘͢อͭ