para 0.9.3.2 → 0.9.3.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/para/cloneable/include_tree_builder.rb +46 -14
- data/lib/para/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8f742ef6484e0ccd595c1a79e219f4cb2a03c72a7fbf9f584990c638412f19e0
|
4
|
+
data.tar.gz: 8c231925d6c2ecc4d0eb7208c5c4b530410d1a30d8a1276d849f31d3e52f5f76
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e42df31fcb4d4d490f5b5127939494fbc9e07855ee1123fd720f089c2e36737b4e1f706b347d36699270ed00eeeb4a228ca81050bdc8ae35b84bbde8a7dfd7b6
|
7
|
+
data.tar.gz: 707696ad2b1f6a2c43f6944f6543ca5dd8dd5a17c3c91942d0d3c38b43e5d2c652d1b76a35409c2de0019c11658f81a6922931d3e4126a6490a77ed189bd8e8a
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Para
|
2
4
|
module Cloneable
|
3
5
|
# This object acts as a service to compile a nested cloneable options hash to be
|
@@ -49,7 +51,7 @@ module Para
|
|
49
51
|
# }
|
50
52
|
#
|
51
53
|
class IncludeTreeBuilder
|
52
|
-
attr_reader :resource,
|
54
|
+
attr_reader :resource, :cloneable_options
|
53
55
|
|
54
56
|
def initialize(resource)
|
55
57
|
@resource = resource
|
@@ -73,26 +75,56 @@ module Para
|
|
73
75
|
# if it exist, which include the attributes that shouldn't be duplicated when
|
74
76
|
# the resource is cloned.
|
75
77
|
#
|
76
|
-
def build_cloneable_options_tree(resource)
|
78
|
+
def build_cloneable_options_tree(resource, path = [])
|
77
79
|
cloneable_options = resource.cloneable_options
|
78
|
-
options = {}
|
79
80
|
|
80
81
|
# Iterate over the resource's cloneable options' :include array and recursively
|
81
82
|
# add nested included resources to its own included resources.
|
82
83
|
options = cloneable_options[:include].each_with_object({}) do |reflection_name, hash|
|
84
|
+
# This avoids cyclic dependencies issues by stopping nested association
|
85
|
+
# inclusions before the cycle starts.
|
86
|
+
#
|
87
|
+
# For example, if a post includes its author, and the author includes its posts,
|
88
|
+
# this would make the system fail with a stack level too deep error. Here this
|
89
|
+
# guard allows the inclusion to stop at :
|
90
|
+
#
|
91
|
+
# { posts: { author: { posts: { author: {}}}}}
|
92
|
+
#
|
93
|
+
# Which ensures that, using the dictionary strategy of deep_cloneable, all
|
94
|
+
# posts' authors' posts will have their author mapped to an already cloned
|
95
|
+
# author when it comes to cloning the "author" 4th level of the include tree.
|
96
|
+
#
|
97
|
+
# This is not the most optimized solution, but works well enough as if the
|
98
|
+
# author's posts match previously cloned posts, they won't be cloned as they'll
|
99
|
+
# exist in the cloned resources dictionary.
|
100
|
+
next if path.length >= 4 &&
|
101
|
+
path[-4] == path[-2] &&
|
102
|
+
path[-2] == reflection_name &&
|
103
|
+
path[-3] == path[-1]
|
104
|
+
|
83
105
|
hash[reflection_name] = {}
|
84
106
|
|
85
|
-
|
86
|
-
|
87
|
-
|
107
|
+
unless (reflection = resource.class.reflections[reflection_name.to_s])
|
108
|
+
next
|
109
|
+
end
|
88
110
|
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
add_reflection_options(
|
111
|
+
reflection_options = hash[reflection_name]
|
112
|
+
association_target = resource.send(reflection_name)
|
113
|
+
|
114
|
+
if reflection.collection?
|
115
|
+
association_target.each do |nested_resource|
|
116
|
+
add_reflection_options(
|
117
|
+
reflection_options,
|
118
|
+
nested_resource,
|
119
|
+
[*path, reflection_name]
|
120
|
+
)
|
95
121
|
end
|
122
|
+
else
|
123
|
+
add_reflection_options(
|
124
|
+
reflection_options,
|
125
|
+
association_target,
|
126
|
+
[*path, reflection_name]
|
127
|
+
)
|
96
128
|
end
|
97
129
|
end
|
98
130
|
|
@@ -104,11 +136,11 @@ module Para
|
|
104
136
|
options
|
105
137
|
end
|
106
138
|
|
107
|
-
def add_reflection_options(reflection_options, nested_resource)
|
139
|
+
def add_reflection_options(reflection_options, nested_resource, path)
|
108
140
|
options = nested_resource.class.try(:cloneable_options)
|
109
141
|
return reflection_options unless options
|
110
142
|
|
111
|
-
target_options = build_cloneable_options_tree(nested_resource)
|
143
|
+
target_options = build_cloneable_options_tree(nested_resource, path)
|
112
144
|
reflection_options.deep_merge!(target_options)
|
113
145
|
end
|
114
146
|
|
data/lib/para/version.rb
CHANGED