Class: Rumbly::Model::ActiveRecord::Relationship

Inherits:
Relationship
  • Object
show all
Defined in:
lib/rumbly/model/active_record/relationship.rb

Overview

This class is an ActiveRecord-specific implementation of the abstract Rumbly::Model::Relationship class used to represent declared relationships (associations) between model classes in the currently loaded environment.

Constant Summary

Constants inherited from Relationship

Relationship::ATTRIBUTES, Relationship::RELATIONSHIP_TYPES

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Relationship

#<=>, #label, #navigable?

Methods included from Rumbly::Model::Abstract

#stub_required_methods

Constructor Details

#initialize(app, association, type = nil, source = nil, target = nil) ⇒ Relationship

Initializes a new Relationship using the given ActiveModel association (in the case of non-generalizations), or the given type, source, and target in the case of generalizations.



52
53
54
55
56
57
58
# File 'lib/rumbly/model/active_record/relationship.rb', line 52

def initialize (app, association, type=nil, source=nil, target=nil)
  @app = app
  @association = association
  @type = type
  @source = source
  @target = target
end

Class Method Details

.all_associations(app) ⇒ Object

Returns all ActiveRecord associations for all model classes in the currently loaded environment.



45
46
47
# File 'lib/rumbly/model/active_record/relationship.rb', line 45

def self.all_associations (app)
  app.klasses.map(&:cls).compact.map(&:reflect_on_all_associations).flatten
end

.all_from_active_record(app) ⇒ Object

Returns an array of Rumbly::Model::ActiveRecord::Relationship objects that represent both associations and generalizations (i.e. subclasses) in the currently loaded ActiveRecord environment.



15
16
17
# File 'lib/rumbly/model/active_record/relationship.rb', line 15

def self.all_from_active_record (app)
  all_from_assocations(app) + all_from_generalizations(app)
end

.all_from_assocations(app) ⇒ Object

Returns an array of Rumbly::Model::ActiveRecord::Relationship objects that represent declared associations between model classes.



21
22
23
# File 'lib/rumbly/model/active_record/relationship.rb', line 21

def self.all_from_assocations (app)
  all_associations(app).map { |a| new(app, a) }
end

.all_from_generalizations(app) ⇒ Object

Returns an array of Rumbly::Model::ActiveRecord::Relationship objects that represent all subclass relationships between model classes.



27
28
29
30
31
32
33
# File 'lib/rumbly/model/active_record/relationship.rb', line 27

def self.all_from_generalizations (app)
  app.klasses.map(&:cls).compact.reject(&:descends_from_active_record?).map do |c|
    source = c.superclass.name
    target = c.name
    new(app, nil, :generalization, source, target)
  end
end

.associations_matching(app, type, option) ⇒ Object

Returns an Array of ActiveRecord associations which match the given type and have the given option, e.g. :belongs_to and :polymorphic.



37
38
39
40
41
# File 'lib/rumbly/model/active_record/relationship.rb', line 37

def self.associations_matching (app, type, option)
  all_associations(app).select { |a| a.macro == type }.select do |a|
    a.options.keys.include?(option)
  end
end

Instance Method Details

#multiplicityObject

Returns the multiplicity of this Relationship based on the type of the ActiveRecord association, e.g. :has_one, :has_many, :belongs_to, etc.



108
109
110
# File 'lib/rumbly/model/active_record/relationship.rb', line 108

def multiplicity
  (type == :generalization) ? nil : (@multiplicity ||= derive_multiplicity)
end

#nameObject

Returns the name of this Relationship, which is just the name from the ActiveRecord association (or nil if this Relationship doesn’t have an association, i.e. it’s a generalization).



102
103
104
# File 'lib/rumbly/model/active_record/relationship.rb', line 102

def name
  (type == :generalization) ? nil : (@name ||= @association.name)
end

Returns true, since ActiveRecord doesn’t have the concept of non-navigable assocations.



119
120
121
# File 'lib/rumbly/model/active_record/relationship.rb', line 119

def navigable
  true
end

#sourceObject

Returns the source Klass for this Relationship. Gets the ActiveRecord model class that’s the source of the underlying association and looks up the corresponding Klass object in our cache.



88
89
90
# File 'lib/rumbly/model/active_record/relationship.rb', line 88

def source
  @source ||= @app.klass_by_name(@association.active_record.name)
end

#targetObject

Returns the target Klass for this Relationship. Gets the ActiveRecord model class that’s the target of the underlying association and looks up the corresponding Klass object in our cache.



95
96
97
# File 'lib/rumbly/model/active_record/relationship.rb', line 95

def target
  @target ||= @app.klass_by_name(@association.klass.name)
end

#throughObject

Returns the “through” class declared



113
114
115
# File 'lib/rumbly/model/active_record/relationship.rb', line 113

def through
  (type == :generalization) ? nil : (@through ||= find_through_klass)
end

#typeObject

Returns the UML relationship type for this Relationship. For a relationships that’s a generalization (subclass), the type is set upon initialization. Otherwise, this method examines the ActiveRecord association for clues that point to the relationship being a simple association, an aggregation, or the even stronger composition.



65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
# File 'lib/rumbly/model/active_record/relationship.rb', line 65

def type
  if @type.nil?
    # relationships are simple associations by default
    @type = :association
    if [:has_one, :has_many].include?(@association.macro)
      autosaves = @association.options[:autosave]
      dependent = @association.options[:dependent]
      # if this association auto-saves or nullifies, assume aggregation
      if autosaves || dependent == :nullify
        @type = :aggregation
      end
      # if this association destroys dependents, assume composition
      if dependent == :destroy || dependent == :delete
        @type = :composition
      end
    end
  end
  return @type
end