Module: ActiveRecord::Mti::ClassMethods

Defined in:
lib/mti.rb

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.as_base_instanceObject

Thread safe execution of a block in a “base instance mode”



55
56
57
58
59
60
61
62
# File 'lib/mti.rb', line 55

def self.as_base_instance
  @@base_instance_mode_lock.synchronize do
    @@base_instance_mode = true
    result = yield
    @@base_instance_mode = false
    result
  end
end

.instantiate(*_) ⇒ Object

Override ActiveRecord’s instantiation method which builds an object from a record Return the base class object when in “base instance mode” and the implementation object otherwise



46
47
48
49
50
51
52
# File 'lib/mti.rb', line 46

def self.instantiate(*_)
  if @@base_instance_mode
    super
  else
    super.public_send(mti_name)
  end
end

Instance Method Details

#mti_baseObject



27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
# File 'lib/mti.rb', line 27

def mti_base
  class_attribute :mti_name
  self.mti_name = self.to_s.underscore.to_sym

  @@base_instance_mode = false
  @@base_instance_mode_lock = Mutex.new

  # Always fetch with the implementation
  default_scope lambda { includes(mti_name) }

  # Implementation model association
  belongs_to mti_name,
             polymorphic: true,
             inverse_of: mti_name

  # Override ActiveRecord's instantiation method
  # which builds an object from a record
  # Return the base class object when in "base instance mode"
  # and the implementation object otherwise
  def self.instantiate(*_)
    if @@base_instance_mode
      super
    else
      super.public_send(mti_name)
    end
  end

  # Thread safe execution of a block in a "base instance mode"
  def self.as_base_instance
    @@base_instance_mode_lock.synchronize do
      @@base_instance_mode = true
      result = yield
      @@base_instance_mode = false
      result
    end
  end
end

#mti_implementation_of(mti_base_name) ⇒ Object



65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
# File 'lib/mti.rb', line 65

def mti_implementation_of(mti_base_name)
  class_attribute :mti_base
  self.mti_base = mti_base_name.to_s.classify.constantize

  # Base model association
  has_one mti_base_name.to_sym,
          :as => mti_base_name.to_sym,
          :autosave => true,
          :dependent => :destroy,
          :validate => true,
          :inverse_of => mti_base_name.to_sym

  # When calling the base object from the implementation
  # switch the base's class to the "base instance mode"
  # to receive the base class object instead of another
  # implementation object and avoid an infinite loop
  define_method "#{mti_base_name}_with_reverse" do          # def role_with_reverse
    mti_base.as_base_instance do                            #   Role.as_base_instance do
      send("#{mti_base_name}_without_reverse")              #     role_without_reverse
    end                                                     #   end
  end                                                       # end
  alias_method_chain mti_base_name, :reverse                # alias_method_chain :role, :reverse

  # Auto build base model
  define_method "#{mti_base_name}_with_autobuild" do        # def role_with_autobuild
    public_send("#{mti_base_name}_without_autobuild") ||    #   role_without_autobuild ||
        public_send("build_#{mti_base_name}")               #     build_role
  end                                                       # end
  alias_method_chain mti_base_name, :autobuild              # alias_method_chain :role, :autobuild

  # Delegate attributes
  mti_base.content_columns.map(&:name).each do |attr|
    delegate attr, "#{attr}=", "#{attr}?",
             :to => mti_base_name.to_sym
  end

  # Delegate associations
  mti_base.reflections.keys
          .tap { |k| k.delete(mti_base_name.to_sym) }
          .each do |association|
    delegate association, "#{association}=",
             :to => mti_base_name.to_sym
  end

  delegate_missing_to mti_base_name

  accepts_nested_attributes_for mti_base_name

  define_method "#{mti_base_name}_id" do
    public_send(mti_base_name).id
  end
end