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

読んで理解するActiveRecordの設計とActiveSupport::Concern

Yuta Totz
November 04, 2015

 読んで理解するActiveRecordの設計とActiveSupport::Concern

Reading Rails - ActiveRecord::Base / ActiveSupport::Concern by @totzyuta

読んで理解するActiveRecordの設計とActiveSupport::Concern - メタプロRuby第二版 by @totzyuta

1. 今日学ぶこと
2. Railsの重要なコンポーネント
3. ソースコードの取得
4. Railsでかい
5. ActiveRecordの設計
6. ActiveRecordでかい
7. ActiveRecord 復習
8. ActiveRecordはどのようにまとめられているか
9. ActiveRecordソースコード
10. ActiveRecord::Base
11. validateはどこに?
12. validateはどこに?②
13. validateはどこに?③ ActiveModelってなんぞ
14. validateはどこに?④ ActiveModelはなぜ必要か
15. validate?の旅
16. ActiveRecordの設計まとめ
17. Concernの設計
18. Concern以前のRails - includeとextendのトリック
19. Concern以前のRails - includeとextendのトリック②
20. includeとextendのトリックの問題点
21. includeとextendのトリックの問題点②
22. includeとextendのトリックの問題点③
23. Rails2での改修工事
24. ActiveSupport::Concern
25. ActiveSupport::Concernモジュール
26. ActiveSupport::Concern仕組み
27. Module#append_features (寄り道)
28. Concern#append_features
29. Concern#append_features 詳細①
30. Concern#append_features 詳細②
31. ActiveModel::Validationsでの使われ方
32. ActiveSupport::Concernクラスまとめ
33. まとめ

Yuta Totz

November 04, 2015
Tweet

More Decks by Yuta Totz

Other Decks in Programming

Transcript

  1. ActiveRecordͰ͔͍ • activerecord/*.rb: 98991ߦ (2015/11/01) • 98991 / 279929 =

    0.35 $ wc -l `find ./activerecord/* -name ‘*.rb’` 98991 total
  2. ActiveRecord ෮श class Duck < ActiveRecord::Base validate do errors.add(:base, “Illegal

    duck name, “) unless name[0] == ‘D’ end end • ActiveRecord::Base͕ϚοϐϯάΫϥεͷεʔύʔΫϥεʹͳ Δɻ • DuckΫϥεΛducksςʔϒϧʹϚοϐϯάͯ͠ɺͦͷattribute ʹΞΫηε͢ΔΰʔετϝιουΛఆٛ͢Δɻ
  3. ActiveRecord͸ͲͷΑ͏ʹ·ͱΊΒΕ͍ͯΔ͔ • ActiveSupportͱActiveModelͷ̎ͭͷϥΠϒϥϦʹେ͖͘ґଘ͠ ͍ͯΔɻ(ޙड़) • autoloadͰϞδϡʔϧΛrequire͢Δ • e.g. ࠷ॳʹActiveRecord::BaseΛ࢖͏࣌ʹɺͦͷΫϥεΛఆٛ ͍ͯ͠ΔϑΝΠϧ

    active_record/base.rbͷϑΝΠϧΛautoload ͕ࣗಈతʹrequire͢Δ • extend ActiveSupport::Autoload ͯ͠ΔͷͰautoload͸ ActiveRecordϞδϡʔϧͷΫϥεϝιουʹͳΔɻ(Ϋϥε֦ு)
  4. # activerecord/lib/active_record.rb require 'active_support' require 'active_model' # … module ActiveRecord

    extend ActiveSupport::Autoload autoload :Base autoload :Callbacks # … ActiveRecord
  5. ActiveRecord::Base • େྔͷϞδϡʔϧΛ extend && include • run_load_hooks Φʔτϩʔυ͞ΕͨϞδϡʔϧ͕ઃఆ༻ͷίʔυΛݺͼग़ͤΔΑ ͏ʹ͢Δ΋ͷɻ=>

    Base͕includeͨ͠Ϟδϡʔϧ͕͞ΒʹϞδϡʔϧΛinclude͠ ͍ͯΔ • autoloadͷ͓͔͛ͰɺιʔείʔυΛActiveRecord::BaseͰrequire͔ͯ͠Β include͢Δඞཁ͕ͳ͍ɻ(include͚ͩͰ؆ܿʹʂ) • ͜͜Λى఺ʹͲͷϝιου͕ͲͷϑΝΠϧͰఆٛ͞ΕͯΔͷ͔୳ͤ͹͍͍ײ͡ʂ (ଟ෼) • saveͳͲͷӬଓԽͷϝιου͸ɺActiveRecord::Persistenceʹ͋Δ
  6. # activerecord/lib/base.rb module ActiveRecord class Base extend ActiveModel::Naming extend ActiveSupport::Benchmarkable

    extend ActiveSupport::DescendantsTracker extend ConnectionHandling extend QueryCache::ClassMethods extend Querying extend Translation extend DynamicMatchers # … extend Enum extend Delegation::DelegateCache include Core include Persistence include ActiveModel::SecurePassword include AutosaveAssociation # … include AutosaveAssociation end ActiveSupport.run_load_hooks(:active_record, Base) end
  7. validate͸Ͳ͜ʹʁ - ActiveModelͬͯͳΜͧʁ • ActiveRecord͔Β͸ಠཱ͍ͯ͠Δ => ActionPack͕ඇ ActiveRecordͳϞσϧͱ΍ΓͱΓ͢ΔͨΊʹ࢖͏ Helperͷ໾ׂ΋࣋ͬͯΔ (Rails

    Guides) • ActiveSupport::ConcernΛ࢖ͬͯΔͷͰɺΫϥε͕Ϟ δϡʔϧΛinclude͢ΔͱΠϯελϯεϝιουͱಉ࣌ ʹvalidateΈ͍ͨͳΫϥεϝιου·ͰҰॹʹखʹೖ Δ (10ষͰṖղ͖)
  8. validate͸Ͳ͜ʹʁ - ActiveModel͸ͳͥඞཁ͔ • validate͸΋ͱ΋ͱActiveRecord::ValidationsͰఆٛ͞Ε͍ͯͨ • ʮDBͷૢ࡞ʯͱʮΦϒδΣΫτϞσϧͷૢ࡞ʯ͸ผʑʹ෼཭͢Δํ͕͍͍Μ ͡Όͳ͍͔ (੹຿ͷ୯ҰԽ) •

    DBͷૢ࡞…อଘɺಡΈࠐΈ => ActiveRecord • ΦϒδΣΫτϞσϧͷૢ࡞…ଐੑΛอ࣋ɺଐੑ͕ଥ౰͔Λ௥੻͢Δ => ActiveModel • valid? : ΦϒδΣΫτ͕σʔλϕʔεʹอଘ͞Ε͔ͨͲ͏͔Λ֬ೝ͢Δඞཁ͕ ͋ΔͷͰActiveRecord • validate : ΦϒδΣΫτͷଐੑͷଥ౰ੑΛνΣοΫ͢Δ͚ͩͳͷͰActiveModel
  9. ActiveRecordͷઃܭ·ͱΊ • ActiveRecord::Base͸ɺϞδϡʔϧͷू·Γ • ͦΕͧΕͷϞδϡʔϧ͕ɺActiveRecord::BaseʹΠϯελϯεϝιουͱΫ ϥεϝιουΛ௥Ճ͢Δ • BaseΫϥεʹ͸ɺΠϯελϯεϝιου͕300ݸҎ্ɺΫϥεϝιου͕ 500ݸҎ্(!!) •

    ͜Ε͕Rubyͷઃܭٕ๏ (ઃܭٕ๏͸ઈରͰ͸ͳ͘ɺݴޠʹΑͬͯҧͬͯ͘Δ) • ૄ݁߹ੑɺςετ༰қੑɺϞδϡʔϧͷ࠶ར༻ੑ • ActiveRecord::BaseΛແࢹͯ͠ActiveModel::ValidationsΫϥε͚ͩ includeͯ͠validateϝιουΛར༻͢Δ͜ͱ΋Ͱ͖Δ
  10. ConcernҎલͷRails - includeͱextendͷτϦοΫ 1. ActiveRecord::Base͕Validations Λinclude 2. ActiveRecord::BaseΛҾ਺(base)ʹ ͯ͠Validationsͷincludedϝιο υ͕ݺ͹ΕΔ

    3. ϑοΫϝιουͷதͰɺBase͕ ClassMethodsϞδϡʔϧΛextend ͢Δ 4. ClassMethodsͷΠϯελϯεϝ ιουୡ͕ɺBaseͷΫϥεϝιο υͱͯ͠௥Ճ͞ΕΔʂ module ActiveRecord module Validations def self.included(base) base.extend ClassMethods # … end module ClassMethods def validates_length_of(*attrs) # … end end def valid? # … end end end
  11. ConcernҎલͷRails - includeͱextendͷτϦοΫ • ϞδϡʔϧΛinclude͢ΔҰߦ͚ͩͰΠϯελϯεϝιουͱΫϥε ϝιουͷ྆ํΛऔΓࠐΊΔʂ • Ͱ΋ΫϥεϝιουΛ࢖͏͋ΒΏΔΫϥεͰincludedϝιουΛ࣮૷ ͠ͳ͖Ό͍͚ͳ͍ •

    includerʹҰߦ଍͢ vs औΓࠐ·ΕΔϞδϡʔϧͰincludedશ෦ఆٛ ͢Δ class Base include Validations extend Validations::ClassMethods # … end module Validations def self.included(base) base.extend ClassMethods # … end # … end
  12. includeͱextendͷτϦοΫͷ໰୊఺ module SecondLevelModule def self.included(base) base.extend ClassMethods end def second_level_instance_method;

    ‘ok’; end module ClassMethods def second_level_class_method; ‘ok’; end end end module FirstLevelModule def self.included(base) base.extend ClassMethods end def first_level_instance_method; ‘ok’; end module ClassMethods def first_level_class_method; ‘ok’; end end include SecondLevelModule end class BaseClass include FirstLevelModule end
  13. includeͱextendͷτϦοΫͷ໰୊఺ $ curl -O https://raw.githubusercontent.com/ totzyuta/magick-of-ruby/master/workshop/chapter10/ chained_inclusions_broken.rb $ pry -r

    ‘./chained_inclusions_broken.rb’ pry>BaseClass.new.first_level_instance_method pry>BaseClass.new.second_level_instance_method pry>BaseClass.first_level_class_method pry>BaseClass.second_level_class_method
  14. module FirstLevelModule def self.included(base) base.extend ClassMethods base.send :include, SecondLevelModule end

    Rails2Ͱͷվम޻ࣄ • includedͱextendͷτϦοΫ͸FirstLevelModule͚ͩͰ࢖͏͜ͱʹ • FirstLevelModule#includedͷதͰɺΠϯΫϧʔμʔʹ SecondLevelModuleΛincludeͤ͞Δ • => include͞ΕΔmodule͸ɺࣗ෼͕ͲͷϨϕϧͰinclude͞ΕΔͷ ͔ؾʹ͓ͯ͘͠ඞཁ͋ΔʂʢͭΒͦ͏ʣ JODMVEF͕Ҏલ͸QSJWBUFͩͬͨɻ ͳͥʁ ౴͑ http://stackoverflow.com/questions/ 4213837/on-ruby-why-include-is- private-and-extend-is-public 2.0.0 ͩͱNoMethodErrorʹͳͬͨ
  15. ActiveSupport::Concern ࢖͍ํ require "active_support" module IncludedClass extend ActiveSupport::Concern def an_instance_method;

    "instance method"; end module ClassMethods def a_class_method; "class method"; end end end class BaseClass include IncludedClass end pry>BaseClass.new.an_instance_m ethod => ??? pry>BaseClass.a_class_method => ???
  16. Module#append_features (دΓಓ) • Rubyͷඪ४ϥΠϒϥϦ • Module#includedͱࣅͯΔɻ͚Ͳҧ͏ɻ • include͞ΕͨϞδϡʔϧ͕ɺΠϯΫϧʔμʔͷܧঝνΣʔϯ ʹؚ·Ε͍ͯΔ͔Ͳ͏͔Λ֬ೝ͔ͯ͠Β௥Ճ͢Δ •

    append_featuresΛΦʔόʔϥΠυ͢ΔͱɺϞδϡʔϧ͕ include͞Εͳ͘ͳͬͯ͠·͏ (!!) => ී௨͸ɺ΋ͱ΋ͱ͸ۭ ͳϑοΫϝιουͰ͋Δincludedͱ͔ΛΦʔόʔϥΠυ͠Α ͏
  17. module ActiveSupport module Concern def append_features(base) if base.instance_variable_defined?(:@_dependencies) base.instance_variable_get(:@_dependencies) <<

    self return false else return false if base < self @_dependencies.each { |dep| base.include(dep) } super base.extend const_get(:ClassMethods) if const_defined?(:ClassMethods) base.class_eval(&@_included_block) if instance_variable_defined?(:@_included_block) end end end end Concern#append_features
  18. Concern#append_features ৄࡉᶃ ΠϯΫϧʔμʔ͕concernͷͱ͖ • @_dependenciesʹselfΛೖ ΕΔ • => ґଘؔ܎৘ใʹࣗ෼ࣗ਎ (concernΫϥε)Λ௥Ճ͢Δ

    • includeͯ͠ͳ͍͜ͱΛࣔ͢ ͨΊʹfalseΛฦ͢ def append_features(base) if base.instance_variable_defined?(:@_dependencies) # concernͷͱ͖ base.instance_variable_get(:@_dependencies) << self return false else # concern͡Όͳ͍ͱ͖ # … end end
  19. Concern#append_features ৄࡉᶄ ΠϯΫϧʔμʔ͕concernͰͳ͍ͱ͖ • ܧঝνΣʔϯʹࣗ෼͕͍Δͱ͖͸ɺincludeͤͣʹfalseΛฦ͢ • ΠϯΫϧʔμʔ(͍͕ͭ͜ྫ͑͹Baseͱ͔ʹͳͬͯΔʂ)ʹࠓ·Ͱґଘؔ܎഑ྻʹετοΫ͖ͯͨ͠Ϋϥ εΛͲ͔Ͳ͔include͍ͯ͘͠ • Module.append_featuresͰࣗ෼ࣗ਎ΛܧঝνΣʔϯʹ௥Ճ͢Δ

    • ClassMethodsΛBaseͰextendͯ͠ΫϥεϝιουΛ௥Ճ͢Δ # concern͡Όͳ͍ͱ͖ return false if base < self @_dependencies.each { |dep| base.include(dep) } super base.extend const_get(:ClassMethods) if const_defined?(:ClassMethods) base.class_eval(&@_included_block) if instance_variable_defined?(:@_included_block) ܧঝؔ܎Λ൑ఆͯ͠CPPMFBOΛฦ͢ $PODFSOϞδϡʔϧͰ͸ͳ͘ɺTFMG DPODFSO ͷείʔϓͰఆ਺ΛಡΈࠐΉɹ const_getΛ࢖Θͳ͍৔߹ɺ ActiveSupport::Concern::ClassMethods Λࢀরͯ͠͠·͏ɻ
  20. ActiveSupport::Concern·ͱΊ • ॏෳͩΒ͚ͷincludeͱextendͷτϦοΫΛ֎෦πʔϧͱͯ͠Χ ϓηϧԽͨ͠΋ͷ • ʮconcernͷͳ͔ͰɺผͷconcernΛincludeͤͣʹޙͰ·ͱΊͯ include͢Δʯ͜ͱͰ࣮ݱ • ରཱ͢Δҙݟ •

    Concerns͸includeͷཪଆͰେྔͷຐ๏Λ࢖ͬͯΔͷͰɺίε τʹͳΔͷͰ͸ʁ • Concernͷ͓͔͛ͰRailsͷϞδϡʔϧ͕εϦϜͰγϯϓϧʹ ͳͬͨ