Class: PaperTrailDiff::AssociationTraversal
- Inherits:
-
Object
- Object
- PaperTrailDiff::AssociationTraversal
- Defined in:
- lib/paper_trail_diff/association_traversal.rb,
sig/generated/paper_trail_diff/association_traversal.rbs
Overview
Resolves and validates ActiveRecord reflections for a bounded association tree.
Instance Method Summary collapse
-
#collect_reflections(model_class, tree, path:) ⇒ Array[Array[untyped]]
: (untyped, AssociationTree, path: String) -> Array[Array[untyped]].
-
#ensure_habtm_history!(model_class, version) ⇒ void
: (untyped, untyped) -> void.
-
#habtm_paths(model_class) ⇒ Array[String]
: (untyped) -> Array.
-
#habtm_reflection?(reflection) ⇒ Boolean
: (untyped) -> bool.
-
#incoming_relationship_columns(reflection) ⇒ Array[String]
: (untyped) -> Array.
-
#initialize(tree) ⇒ AssociationTraversal
constructor
: (AssociationTree) -> void.
-
#join_path(parent, name) ⇒ String
: (String, String) -> String.
-
#paper_trail_versions?(model_class, reflection) ⇒ Boolean
: (untyped, untyped) -> bool.
-
#reflections_for(model_class, tree, path:) ⇒ Array[untyped]
: (untyped, AssociationTree, path: String) -> Array.
-
#requested_reflections(model_class, tree, path) ⇒ Array[untyped]
: (untyped, AssociationTree, String) -> Array.
-
#resolve_reflection(model_class, name, full_path) ⇒ Object
: (untyped, String, String) -> untyped.
-
#selected_reflections(model_class) ⇒ Array[Array[untyped]]
: (untyped) -> Array[Array[untyped]].
-
#validate!(model_class) ⇒ void
: (untyped) -> void.
-
#validate_tree!(model_class, tree, path:) ⇒ void
: (untyped, AssociationTree, path: String) -> void.
Constructor Details
#initialize(tree) ⇒ AssociationTraversal
: (AssociationTree) -> void
8 9 10 11 |
# File 'lib/paper_trail_diff/association_traversal.rb', line 8 def initialize(tree) @tree = tree @reflection_cache = {} end |
Instance Method Details
#collect_reflections(model_class, tree, path:) ⇒ Array[Array[untyped]]
: (untyped, AssociationTree, path: String) -> Array[Array[untyped]]
66 67 68 69 70 71 72 73 74 75 |
# File 'lib/paper_trail_diff/association_traversal.rb', line 66 def collect_reflections(model_class, tree, path:) reflections_for(model_class, tree, path: path).flat_map do |reflection| child_path = join_path(path, reflection.name.to_s) result = [[child_path, reflection]] subtree = tree.child(reflection.name) next result unless subtree && !subtree.empty? && !reflection.polymorphic? result + collect_reflections(reflection.klass, subtree, path: child_path) end end |
#ensure_habtm_history!(model_class, version) ⇒ void
This method returns an undefined value.
: (untyped, untyped) -> void
24 25 26 27 28 29 30 31 |
# File 'lib/paper_trail_diff/association_traversal.rb', line 24 def ensure_habtm_history!(model_class, version) paths = habtm_paths(model_class) return if paths.empty? return if version.respond_to?(:transaction_id) && version.transaction_id = "HABTM history is incomplete at version #{version.id}: #{paths.join(', ')}" raise IncompleteAssociationHistoryError, end |
#habtm_paths(model_class) ⇒ Array[String]
: (untyped) -> Array
34 35 36 37 38 |
# File 'lib/paper_trail_diff/association_traversal.rb', line 34 def habtm_paths(model_class) selected_reflections(model_class).filter_map do |path, reflection| path if habtm_reflection?(reflection) end.freeze end |
#habtm_reflection?(reflection) ⇒ Boolean
: (untyped) -> bool
119 120 121 122 123 124 |
# File 'lib/paper_trail_diff/association_traversal.rb', line 119 def habtm_reflection?(reflection) return true if reflection.macro == :has_and_belongs_to_many return false unless reflection.[:through] habtm_reflection?(reflection.through_reflection) end |
#incoming_relationship_columns(reflection) ⇒ Array[String]
: (untyped) -> Array
47 48 49 50 51 52 53 54 55 56 57 58 |
# File 'lib/paper_trail_diff/association_traversal.rb', line 47 def incoming_relationship_columns(reflection) direct = %i[has_one has_many].include?(reflection.macro) && !reflection.[:through] return [] unless direct foreign_keys = Array(reflection.foreign_key) # @type var foreign_keys: Array[untyped] columns = foreign_keys.map do |column| # rubocop:disable Style/SymbolProc column.to_s end columns << reflection.type.to_s if reflection.[:as] columns end |
#join_path(parent, name) ⇒ String
: (String, String) -> String
127 128 129 |
# File 'lib/paper_trail_diff/association_traversal.rb', line 127 def join_path(parent, name) parent.empty? ? name : "#{parent}.#{name}" end |
#paper_trail_versions?(model_class, reflection) ⇒ Boolean
: (untyped, untyped) -> bool
113 114 115 116 |
# File 'lib/paper_trail_diff/association_traversal.rb', line 113 def paper_trail_versions?(model_class, reflection) model_class.respond_to?(:versions_association_name) && reflection.name.to_s == model_class.versions_association_name.to_s end |
#reflections_for(model_class, tree, path:) ⇒ Array[untyped]
: (untyped, AssociationTree, path: String) -> Array
41 42 43 44 |
# File 'lib/paper_trail_diff/association_traversal.rb', line 41 def reflections_for(model_class, tree, path:) key = [model_class.name.to_s, path, tree.object_id] @reflection_cache[key] ||= requested_reflections(model_class, tree, path) end |
#requested_reflections(model_class, tree, path) ⇒ Array[untyped]
: (untyped, AssociationTree, String) -> Array
89 90 91 92 93 |
# File 'lib/paper_trail_diff/association_traversal.rb', line 89 def requested_reflections(model_class, tree, path) tree.children.map do |name, _subtree| resolve_reflection(model_class, name, join_path(path, name)) end.freeze end |
#resolve_reflection(model_class, name, full_path) ⇒ Object
: (untyped, String, String) -> untyped
96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 |
# File 'lib/paper_trail_diff/association_traversal.rb', line 96 def resolve_reflection(model_class, name, full_path) reflection = model_class.reflect_on_association(name.to_sym) raise UnknownAssociationError, "unknown association: #{full_path}" unless reflection if paper_trail_versions?(model_class, reflection) = "unsupported association #{full_path}: PaperTrail versions" raise UnsupportedAssociationError, end unless SUPPORTED_ASSOCIATION_MACROS.include?(reflection.macro) raise UnsupportedAssociationError, "unsupported association #{full_path}: #{reflection.macro}" end reflection end |
#selected_reflections(model_class) ⇒ Array[Array[untyped]]
: (untyped) -> Array[Array[untyped]]
19 20 21 |
# File 'lib/paper_trail_diff/association_traversal.rb', line 19 def selected_reflections(model_class) collect_reflections(model_class, @tree, path: '').freeze end |
#validate!(model_class) ⇒ void
This method returns an undefined value.
: (untyped) -> void
14 15 16 |
# File 'lib/paper_trail_diff/association_traversal.rb', line 14 def validate!(model_class) validate_tree!(model_class, @tree, path: '') end |
#validate_tree!(model_class, tree, path:) ⇒ void
This method returns an undefined value.
: (untyped, AssociationTree, path: String) -> void
78 79 80 81 82 83 84 85 86 |
# File 'lib/paper_trail_diff/association_traversal.rb', line 78 def validate_tree!(model_class, tree, path:) reflections_for(model_class, tree, path: path).each do |reflection| subtree = tree.child(reflection.name) next unless subtree && !subtree.empty? && !reflection.polymorphic? child_path = join_path(path, reflection.name.to_s) validate_tree!(reflection.klass, subtree, path: child_path) end end |