Module: Cistern::Associations

Defined in:
lib/cistern/associations.rb

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.extended(klass) ⇒ Object



4
5
6
7
8
9
10
11
12
# File 'lib/cistern/associations.rb', line 4

def self.extended(klass)
  def klass.association_overlay
    @association_overlay ||= const_set(:Associations, Module.new)
  end

  klass.send(:include, klass.association_overlay)

  super
end

Instance Method Details

#associationsHash{Symbol=>Array}

Lists the associations defined on the resource

Returns:

  • (Hash{Symbol=>Array})

    mapping of association type to name



16
17
18
# File 'lib/cistern/associations.rb', line 16

def associations
  @associations ||= Hash.new { |h, k| h[k] = [] }
end

#belongs_to(name, *args, &block) ⇒ Cistern::Model

Define an assocation that references a model.

Examples:

class Firm < Law::Model
  identity :registration_id
  belongs_to :leader, -> { cistern.employees.get(:ceo) }
 end

Parameters:

  • name (Symbol)

    name of association and corresponding reader.

  • scope (Proc)

    returning a Model that is evaluated within the context of the model.

Returns:



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
# File 'lib/cistern/associations.rb', line 77

def belongs_to(name, *args, &block)
  name_sym = name.to_sym

  reader_method = name
  writer_method = "#{name}="

  options = args.last.is_a?(::Hash) ? args.pop : {}
  scope = args.first || block

  attribute name_sym, options.merge(writer: false, reader: false)

  association_overlay.module_eval do
    define_method reader_method do
      model = instance_exec(&scope)
      attributes[name_sym] = model.attributes
      model
    end
  end

  association_overlay.module_eval do
    define_method writer_method do |model|
      previous_value = attributes[name_sym]
      new_value = model.respond_to?(:attributes) ? model.attributes : model
      attributes[name_sym] = new_value

      changed!(name_sym, previous_value, new_value)

      new_value
    end
  end

  associations[:belongs_to] << name_sym
end

#has_many(name, *args, &block) ⇒ Cistern::Collection

Define an assocation that references a collection.

Examples:

class Firm < Law::Model
  identity :registration_id
  has_many :lawyers, -> { cistern.associates(firm_id: identity) }
 end

Parameters:

  • name (Symbol)

    name of association and corresponding reader and writer.

  • scope (Proc)

    returning Collection instance to load models into. #scope is evaluated within the context of the model.

Returns:



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
64
65
66
# File 'lib/cistern/associations.rb', line 30

def has_many(name, *args, &block)
  name_sym = name.to_sym

  reader_method = name
  writer_method = "#{name}="

  options = args.last.is_a?(::Hash) ? args.pop : {}
  scope = args.first || block

  attribute name_sym, options.merge(writer: false, reader: false, type: :array)

  association_overlay.module_eval do
    define_method reader_method do
      collection = instance_exec(&scope)
      records = attributes[name_sym] || []

      collection.load(records) if records.any?
      collection
    end
  end

  association_overlay.module_eval do
    define_method writer_method do |models|
      previous_value = attributes[name_sym]
      new_value =
        attributes[name_sym] = Array(models).map do |model|
          model.respond_to?(:attributes) ? model.attributes : model
        end

      changed!(name_sym, previous_value, new_value)

      new_value
    end
  end

  associations[:has_many] << name_sym
end