hierarchable 0.3.0 → 0.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Gemfile.lock +1 -1
- data/README.md +12 -13
- data/lib/hierarchable/hierarchable.rb +13 -9
- data/lib/hierarchable/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: c906048aba37ae782246aaceec861dde107dfc1a17aed8be531ed5100f3bb5c2
|
|
4
|
+
data.tar.gz: 6ab096cae6a3fd9d8da70bd222732f513a63b693d414751fa44e6ebe085210eb
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: c31a773cafe33d14b83b63d25a7783ed4c75bb1385458de3e893b3c91530b42e2421c4d59c76d9590cddc6b2260aaef391c4f62b9af5f1ad91c6c0979b439827
|
|
7
|
+
data.tar.gz: 8ebef8dcc55ab798c7abad2f94cd895a6d3778e28c07aadbcc175bfbe1fc40c526d833590783e6c3c94793b6a9579c3ab3ee5c968660ea8e600cb410c6d81da9
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# Hierarchable
|
|
2
2
|
|
|
3
3
|
[](https://dl.circleci.com/status-badge/redirect/gh/prschmid/hierarchable/tree/main)
|
|
4
|
+
[](https://badge.fury.io/rb/hierarchable)
|
|
4
5
|
|
|
5
6
|
A simple way to define cross model hierarchical (parent, child, sibling) relationships between ActiveRecord models.
|
|
6
7
|
|
|
@@ -24,14 +25,14 @@ Or install it yourself as:
|
|
|
24
25
|
|
|
25
26
|
Once the gem is installed, you will need to make sure that your models have the correct columns.
|
|
26
27
|
|
|
27
|
-
* hierarchy_root
|
|
28
|
-
* hierarchy_parent
|
|
29
|
-
* hierarchy_ancestors_path
|
|
28
|
+
* `hierarchy_root`: The root node in the hierarchy hierarchy (polymorphic)
|
|
29
|
+
* `hierarchy_parent`: The parent of the current object (polymorphic)
|
|
30
|
+
* `hierarchy_ancestors_path`: The string representation of all ancestors of
|
|
30
31
|
the current object (string).
|
|
31
32
|
|
|
32
33
|
Assuming that you are using UUIDs for your IDs, this can be done by adding the following to the model(s) for which you wish to have hierarchy information:
|
|
33
34
|
|
|
34
|
-
```
|
|
35
|
+
```ruby
|
|
35
36
|
t.references :hierarchy_root,
|
|
36
37
|
polymorphic: true,
|
|
37
38
|
null: true,
|
|
@@ -59,13 +60,13 @@ We will describe the usage using a simplistic Project and Task analogy where we
|
|
|
59
60
|
class Project
|
|
60
61
|
include Hierarchable
|
|
61
62
|
hierarchable
|
|
62
|
-
# If desired, could explicitly
|
|
63
|
-
# the same
|
|
63
|
+
# If desired, one could explicitly set the parent source to `nil` for clarity,
|
|
64
|
+
# but this is the same as omitting it.
|
|
64
65
|
# hierarchable parent_source: nil
|
|
65
66
|
end
|
|
66
67
|
```
|
|
67
68
|
|
|
68
|
-
This will set up the `Project` as the root of the hierarchy. When a `Project` model is saved, it will not have any values for the hierarchy_root, hierarchy_parent, or hierarchy_ancestors_path. This is because for the root item
|
|
69
|
+
This will set up the `Project` as the root of the hierarchy. When a `Project` model is saved, it will not have any values for the hierarchy_root, hierarchy_parent, or hierarchy_ancestors_path (i.e. they are `nil`). This is because for the root item we are not guaranteed to have an ID for the object until after it is saved. Thus, there is no consistent way for us to set these values across different use cases. This doesn't affect any of the usage of the library, it's just something to keep in mind.
|
|
69
70
|
|
|
70
71
|
```ruby
|
|
71
72
|
project = Project.create!
|
|
@@ -148,7 +149,7 @@ project.hierarchy_descendants
|
|
|
148
149
|
|
|
149
150
|
The major distinction for what is returned is whether you are querying "up the hierarchy" or "down the hierarchy". As there is only 1 path up the hierchy to get to the root, the return values of `hierarchy_ancestors` is a list and `hierarchy_parent` is a single object. However, traversing down the list is a little more tricky as there are various models and potential paths to get all the way do to the leaves. As such, for all methods at the same level or going down the tree (`hierarchy_siblings`, `hierarchy_children`, and `hierarchy_descendants`), the return value is a hash that has the model class as the key, and either a `ActiveRecord::Relation` or a list as the value. For example, for a Project model that has tasks and milestones as descendants, the return value might be something like
|
|
150
151
|
|
|
151
|
-
```
|
|
152
|
+
```ruby
|
|
152
153
|
{
|
|
153
154
|
'Task': [all descendant tasks starting at the project]
|
|
154
155
|
'Milestone': [all descendant milestones starting at the project]
|
|
@@ -166,7 +167,7 @@ All of the methods (except `hierarchy_parent`) take a `models` paramter that can
|
|
|
166
167
|
|
|
167
168
|
There are times when we only need to get the siblings/children/descendants of one type and having a hash returned is a little cumbersome. To deal with this case, you can pass `compact: true` as a parameter and it will return just single result not as a hash. For example:
|
|
168
169
|
|
|
169
|
-
```
|
|
170
|
+
```ruby
|
|
170
171
|
# Returns as a hash of the form `{Task: [..all descendants..]}`
|
|
171
172
|
project.hierarch_descendants(models: ['Task'])
|
|
172
173
|
|
|
@@ -238,7 +239,7 @@ However there are times when we need to manually add a child relation to be insp
|
|
|
238
239
|
|
|
239
240
|
```ruby
|
|
240
241
|
class SomeObject
|
|
241
|
-
include
|
|
242
|
+
include Hierarchable
|
|
242
243
|
hierarched parent_source: :parent,
|
|
243
244
|
additional_descendant_associations: [:some_association]
|
|
244
245
|
end
|
|
@@ -248,14 +249,12 @@ There may also be a case when we want exact control over what associations that
|
|
|
248
249
|
|
|
249
250
|
```ruby
|
|
250
251
|
class SomeObject
|
|
251
|
-
include
|
|
252
|
+
include Hierarchable
|
|
252
253
|
hierarched parent_source: :parent,
|
|
253
254
|
descendant_associations: [:some_association]
|
|
254
255
|
end
|
|
255
256
|
```
|
|
256
257
|
|
|
257
|
-
Note: For the use case that this library was designed (e.g. creating breadcrumbs) this was a limitation that was perfectly acceptible. In the future we may plan to letusers create an optional "ancestry" table to make this more efficient. Once this table exists, inserts and updates will be slower as an extra object will need to be managed, but queries descenants will be improved.
|
|
258
|
-
|
|
259
258
|
### Configuring the separators
|
|
260
259
|
|
|
261
260
|
By default the separators to use for the path and records are `/` and `|` respectively. This means that a hierarchy path will look something like
|
|
@@ -396,6 +396,7 @@ module Hierarchable
|
|
|
396
396
|
until models_to_analyze.empty?
|
|
397
397
|
|
|
398
398
|
klass = models_to_analyze.pop
|
|
399
|
+
next unless klass
|
|
399
400
|
next if models.include?(klass)
|
|
400
401
|
|
|
401
402
|
obj = klass.new
|
|
@@ -514,7 +515,7 @@ module Hierarchable
|
|
|
514
515
|
# also add in the one provided.
|
|
515
516
|
#
|
|
516
517
|
# class A
|
|
517
|
-
# include
|
|
518
|
+
# include Hierarchable
|
|
518
519
|
# hierarched parent_source: :parent,
|
|
519
520
|
# additional_descendant_associations: [:some_association]
|
|
520
521
|
# end
|
|
@@ -523,7 +524,7 @@ module Hierarchable
|
|
|
523
524
|
# that should be used. In that case, we can specify it like this:
|
|
524
525
|
#
|
|
525
526
|
# class A
|
|
526
|
-
# include
|
|
527
|
+
# include Hierarchable
|
|
527
528
|
# hierarched parent_source: :parent,
|
|
528
529
|
# descendant_associations: [:some_association]
|
|
529
530
|
# end
|
|
@@ -682,11 +683,15 @@ module Hierarchable
|
|
|
682
683
|
def hierarchy_parent_changed?
|
|
683
684
|
# FIXME: We need to figure out how to deal with updating the
|
|
684
685
|
# object_hierarchy_ancestry_path, object_hierarchy_full_path, etc.,
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
686
|
+
return true unless persisted?
|
|
687
|
+
|
|
688
|
+
source = hierarchy_parent_source
|
|
689
|
+
return false if source.blank?
|
|
690
|
+
|
|
691
|
+
changed_method = "#{source}_id_changed?"
|
|
692
|
+
return public_send(changed_method) if respond_to?(changed_method)
|
|
693
|
+
|
|
694
|
+
send(source)&.id == hierarchy_parent_id
|
|
690
695
|
end
|
|
691
696
|
|
|
692
697
|
# Update the hierarchy_ancestors_path if the hierarchy has changed.
|
|
@@ -699,7 +704,6 @@ module Hierarchable
|
|
|
699
704
|
def class_for_association(association)
|
|
700
705
|
self.association(association)
|
|
701
706
|
.reflection
|
|
702
|
-
.
|
|
703
|
-
.safe_constantize
|
|
707
|
+
.klass
|
|
704
708
|
end
|
|
705
709
|
end
|
data/lib/hierarchable/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: hierarchable
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.3.
|
|
4
|
+
version: 0.3.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Patrick R. Schmid
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2023-01-18 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: bundler
|