monarchy 2.2.2 → 2.3.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 815ca965ee47bec334658cc90ce50557a8d0154e
4
- data.tar.gz: 8353cc02f268a429bf61b117c421b5481942a2c4
3
+ metadata.gz: 37446023d193a35f3d1989848c858d173810af90
4
+ data.tar.gz: 4db1f53bf50bb8f75995d10d6e4da232f042b1d9
5
5
  SHA512:
6
- metadata.gz: 3a11658a76ea5dc9cf75567c7c2485c0501fb95cc8003ed64b650bfdc13c6ae64db63037ee30b8c79d7c9b2c48a55e585faec53a99e26483f5d260568b55d143
7
- data.tar.gz: aa8c93f91f7a4bcf48154e1207bd7bdfd81f58f5391a8488eade7a16da410a9507286f3425442ab928ff91b1f087b1f4a5646ad9de65d9c6f52fef81796c1a82
6
+ metadata.gz: 7f1f23cb2bde8c85ef10b201e8ae337b70abacdf927cedf9586b8c46a839ca41118d106c925c7ebe163e7ad3ead9e4b0f8e389d6e536d3e34935d3442cacc95f
7
+ data.tar.gz: 7dcbd125eda5e4bc2c6c1afbd94d8382c70f89b54ee176fefad54e893fc84a1e0d6706f9fd802af11ac098ca2b3cd1d25d584ae09319cde4ca08093ce8207b2c
@@ -1 +1 @@
1
- future-release=2.2.2
1
+ future-release=2.3.0
data/CHANGELOG.md CHANGED
@@ -1,7 +1,18 @@
1
1
  # Change Log
2
2
 
3
- ## [2.2.2](https://github.com/Exelord/Monarchy/tree/2.2.2) (2017-06-14)
4
- [Full Changelog](https://github.com/Exelord/Monarchy/compare/v2.2.1...2.2.2)
3
+ ## [2.3.0](https://github.com/Exelord/Monarchy/tree/2.3.0) (2017-06-14)
4
+ [Full Changelog](https://github.com/Exelord/Monarchy/compare/v2.2.2...2.3.0)
5
+
6
+ **Closed issues:**
7
+
8
+ - Remove potential n-query [\#79](https://github.com/Exelord/Monarchy/issues/79)
9
+
10
+ **Merged pull requests:**
11
+
12
+ - Improve performance and specs [\#76](https://github.com/Exelord/Monarchy/pull/76) ([Exelord](https://github.com/Exelord))
13
+
14
+ ## [v2.2.2](https://github.com/Exelord/Monarchy/tree/v2.2.2) (2017-06-14)
15
+ [Full Changelog](https://github.com/Exelord/Monarchy/compare/v2.2.1...v2.2.2)
5
16
 
6
17
  **Fixed bugs:**
7
18
 
data/Gemfile CHANGED
@@ -18,6 +18,7 @@ gemspec
18
18
 
19
19
  group :development, :test do
20
20
  gem 'database_cleaner', '1.5.3'
21
+ gem 'db-query-matchers', '0.8.0'
21
22
  gem 'factory_girl_rails', '4.8.0'
22
23
  gem 'ffaker', '2.5.0'
23
24
  gem 'pry-rails', '0.3.6'
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- monarchy (2.2.2)
4
+ monarchy (2.3.0)
5
5
  active_record_union (= 1.2.0)
6
6
  activerecord (>= 4.2.7.1)
7
7
  closure_tree (= 6.5.0)
@@ -62,6 +62,7 @@ GEM
62
62
  concurrent-ruby (1.0.5)
63
63
  configurations (2.2.2)
64
64
  database_cleaner (1.5.3)
65
+ db-query-matchers (0.8.0)
65
66
  diff-lcs (1.3)
66
67
  docile (1.1.5)
67
68
  erubis (2.7.0)
@@ -190,6 +191,7 @@ DEPENDENCIES
190
191
  bundler (~> 1.12)
191
192
  codeclimate-test-reporter (~> 1.0.8)
192
193
  database_cleaner (= 1.5.3)
194
+ db-query-matchers (= 0.8.0)
193
195
  factory_girl_rails (= 4.8.0)
194
196
  ffaker (= 2.5.0)
195
197
  monarchy!
@@ -18,6 +18,51 @@ We are using [Closure Tree][e5c808aa] behind `Hierarchy` class. There is a bunch
18
18
 
19
19
  [e5c808aa]: https://github.com/mceachen/closure_tree "Closure Tree"
20
20
 
21
+ #### .hierarchies_for
22
+ You can use this method if you want to get all hierarchies for specific resources, eg:
23
+
24
+ ```
25
+ Monarchy.hierarchy_class.hierarchies_for(Project.all) # returns hierarchies
26
+ ```
27
+
28
+ ** Remember: `hierarchies_for` can receive only `ActiveRecord` class argument! **
29
+
30
+ #### .children_for
31
+ You can use this method if you want to get all explicit children for specific hierarchies, eg:
32
+
33
+ ```
34
+ Monarchy.hierarchy_class.children_for(my_hierarchy) # returns children hierarchies
35
+ ```
36
+
37
+ ** Remember: `children_for` can receive only `ActiveRecord` class argument! **
38
+
39
+ #### .parents_for
40
+ You can use this method if you want to get all explicit parents for specific hierarchies, eg:
41
+
42
+ ```
43
+ Monarchy.hierarchy_class.parents_for(my_hierarchy) # returns parents hierarchies
44
+ ```
45
+
46
+ ** Remember: `parents_for` can receive only `ActiveRecord` class argument! **
47
+
48
+ #### .descendants_for
49
+ You can use this method if you want to get all descendants for specific hierarchies, eg:
50
+
51
+ ```
52
+ Monarchy.hierarchy_class.descendants_for(my_hierarchy) # returns descendants hierarchies
53
+ ```
54
+
55
+ ** Remember: `descendants_for` can receive only `ActiveRecord` class argument! **
56
+
57
+ #### .ancestors_for
58
+ You can use this method if you want to get all ancestors for specific hierarchies, eg:
59
+
60
+ ```
61
+ Monarchy.hierarchy_class.ancestors_for(my_hierarchies) # returns ancestors hierarchies
62
+ ```
63
+
64
+ ** Remember: `ancestors_for` can receive only `ActiveRecord` class argument! **
65
+
21
66
  ## Scopes:
22
67
 
23
68
  ### .accessible_for
@@ -1,7 +1,6 @@
1
1
  class MonarchyCreateUsers < ActiveRecord::Migration
2
2
  def change
3
3
  create_table :users do |t|
4
- t.timestamps null: false
5
4
  end
6
5
  end
7
6
  end
@@ -10,15 +10,11 @@ module Monarchy
10
10
  self.table_name = 'monarchy_hierarchies'
11
11
  has_closure_tree dependent: :destroy
12
12
 
13
- has_many :members, class_name: "::#{Monarchy.member_class}", dependent: :destroy
14
- has_many :users, through: :members, class_name: "::#{Monarchy.user_class}"
15
- belongs_to :resource, polymorphic: true
16
-
13
+ include_relations
17
14
  include_scopes
15
+ include_validators
18
16
 
19
- validates :resource_type, presence: true
20
- validates :resource_id, uniqueness: { scope: [:resource_type] }, presence: true
21
-
17
+ extend Monarchy::ActsAsHierarchy::ClassMethods
22
18
  include Monarchy::ActsAsHierarchy::InstanceMethods
23
19
  end
24
20
  end
@@ -29,23 +25,75 @@ module Monarchy
29
25
  end
30
26
  end
31
27
 
28
+ module ClassMethods
29
+ def hierarchies_for(resources)
30
+ check_argument_type(resources)
31
+ resources ? unscoped.where(resource: resources) : none
32
+ end
33
+
34
+ def children_for(hierarchies)
35
+ check_argument_type(hierarchies)
36
+ hierarchies ? unscoped.where(parent: hierarchies) : none
37
+ end
38
+
39
+ def parents_for(hierarchies)
40
+ check_argument_type(hierarchies)
41
+ return none unless hierarchies
42
+
43
+ unscoped.joins('INNER JOIN monarchy_hierarchies AS hierarchies_children ON '\
44
+ 'monarchy_hierarchies.id = hierarchies_children.parent_id')
45
+ .where(hierarchies_children: { id: hierarchies })
46
+ end
47
+
48
+ def descendants_for(hierarchies)
49
+ check_argument_type(hierarchies)
50
+ hierarchies ? unscoped.with_ancestor(hierarchies) : none
51
+ end
52
+
53
+ def ancestors_for(hierarchies)
54
+ check_argument_type(hierarchies)
55
+ return none unless hierarchies
56
+
57
+ unscoped.joins('INNER JOIN monarchy_hierarchy_hierarchies ON '\
58
+ 'monarchy_hierarchies.id = monarchy_hierarchy_hierarchies.ancestor_id')
59
+ .where(monarchy_hierarchy_hierarchies: { descendant_id: hierarchies.select(:id) })
60
+ .where('monarchy_hierarchy_hierarchies.generations > 0')
61
+ end
62
+
63
+ private
64
+
65
+ def check_argument_type(argument)
66
+ condition = argument.nil? || argument.is_a?(ActiveRecord::Base) || argument.is_a?(ActiveRecord::Relation)
67
+ raise(ArgumentError, 'Argument has to be ActiveRecord!') unless condition
68
+ end
69
+ end
70
+
32
71
  module SupportMethods
33
72
  private
34
73
 
74
+ def include_relations
75
+ belongs_to :resource, polymorphic: true
76
+ has_many :members, class_name: "::#{Monarchy.member_class}", dependent: :destroy
77
+ has_many :users, through: :members, class_name: "::#{Monarchy.user_class}"
78
+ end
79
+
80
+ def include_validators
81
+ validates :resource_type, presence: true
82
+ validates :resource_id, uniqueness: { scope: [:resource_type] }, presence: true
83
+ end
84
+
35
85
  # rubocop:disable all
36
86
  def include_scopes
37
87
  scope :in, (lambda do |hierarchy, descendants = true|
38
- Monarchy::Validators.hierarchy(hierarchy)
39
- where(id: descendants ? hierarchy.descendants : hierarchy.children)
88
+ where(id: descendants ? descendants_for(hierarchy) : children_for(hierarchy))
40
89
  end)
41
90
 
42
91
  scope :accessible_for, (lambda do |user, options = {}|
43
- Monarchy::Validators.user(user)
44
92
  user_id = user.id
45
93
 
46
94
  custom_options = accessible_for_options(options)
47
95
  where(id: accessible_roots_ids(user_id, custom_options[:parent_access])
48
- .union_all(accessible_leaves_ids(user_id, custom_options[:inherited_roles])))
96
+ .union_all(accessible_leaves_ids(user_id, custom_options[:inherited_roles])))
49
97
  end)
50
98
  end
51
99
  # rubocop:enable all
@@ -45,18 +45,22 @@ module Monarchy
45
45
  @parentize_name = name
46
46
  end
47
47
 
48
+ # rubocop:disable all
48
49
  def include_scopes
49
50
  scope :in, (lambda do |resource, descendants = true|
50
51
  Monarchy::Validators.resource(resource)
51
- hierarchies = Monarchy.hierarchy_class.in(resource.hierarchy, descendants)
52
+ hierarchy = Monarchy.hierarchy_class.hierarchies_for(resource)
53
+ hierarchies = Monarchy.hierarchy_class.in(hierarchy, descendants)
52
54
  joins(:hierarchy).where(monarchy_hierarchies: { id: hierarchies })
53
55
  end)
54
56
 
55
57
  scope :accessible_for, (lambda do |user, options = {}|
58
+ Monarchy::Validators.user(user)
56
59
  joins(:hierarchy).where(monarchy_hierarchies: { id: Monarchy.hierarchy_class
57
60
  .accessible_for(user, options) })
58
61
  end)
59
62
  end
63
+ # rubocop:enable all
60
64
 
61
65
  def include_relationships
62
66
  has_many :members, through: :hierarchy, class_name: "::#{Monarchy.member_class}"
@@ -67,7 +71,7 @@ module Monarchy
67
71
 
68
72
  module InstanceMethods
69
73
  def parent
70
- @parent = hierarchy.try(:parent).try(:resource) || @parent
74
+ @parent = parent_resource || @parent
71
75
  end
72
76
 
73
77
  def parent=(resource)
@@ -81,7 +85,7 @@ module Monarchy
81
85
  end
82
86
 
83
87
  def children=(array)
84
- hierarchy&.update(children: hierarchies_for(array))
88
+ hierarchy&.update(children: children_hierarchies(array))
85
89
  @children = array
86
90
  end
87
91
 
@@ -91,12 +95,13 @@ module Monarchy
91
95
  self.hierarchy ||= Monarchy.hierarchy_class.create(
92
96
  resource: self,
93
97
  parent: parent.try(:hierarchy),
94
- children: hierarchies_for(children)
98
+ children: children_hierarchies(children)
95
99
  )
96
100
  end
97
101
 
98
- def accessible_for(user)
99
- hierarchy.accessible_for(user)
102
+ def accessible_for(user, options = {})
103
+ Monarchy::Validators.user(user)
104
+ hierarchy.accessible_for(user, options)
100
105
  end
101
106
 
102
107
  private
@@ -117,12 +122,18 @@ module Monarchy
117
122
  end
118
123
 
119
124
  def children_resources
120
- c = hierarchy.try(:children)
121
- return nil if c.nil?
122
- c.includes(:resource).map(&:resource)
125
+ resource_hierarchy = Monarchy.hierarchy_class.hierarchies_for(self)
126
+ hierarchy_children = Monarchy.hierarchy_class.children_for(resource_hierarchy)
127
+ hierarchy_children.includes(:resource).map(&:resource)
123
128
  end
124
129
 
125
- def hierarchies_for(array)
130
+ def parent_resource
131
+ resource_hierarchy = Monarchy.hierarchy_class.hierarchies_for(self)
132
+ hierarchy_parent = Monarchy.hierarchy_class.parents_for(resource_hierarchy)
133
+ hierarchy_parent.first&.resource
134
+ end
135
+
136
+ def children_hierarchies(array)
126
137
  array&.compact!
127
138
  Array(array).map { |resource| Monarchy::Validators.resource(resource).hierarchy }
128
139
  end
@@ -88,8 +88,7 @@ module Monarchy
88
88
  end
89
89
 
90
90
  def resource_roles(resource)
91
- resource_hierarchy = hierarchies_for(resource).select(:id)
92
-
91
+ resource_hierarchy = Monarchy.hierarchy_class.hierarchies_for(resource).select(:id)
93
92
  user_memberships = Monarchy.member_class
94
93
  .where(hierarchy_id: resource_hierarchy, user_id: id)
95
94
  .select(:id, :hierarchy_id).to_sql
@@ -156,34 +155,18 @@ module Monarchy
156
155
  @inherited_default_role ||= Monarchy.role_class.find_by(name: Monarchy.configuration.inherited_default_role)
157
156
  end
158
157
 
159
- # TODO: Make these methods public in related interfaces
160
-
161
158
  def members_for(hierarchies)
162
159
  Monarchy.member_class.where(hierarchy: hierarchies, user_id: id)
163
160
  end
164
161
 
165
- def hierarchies_for(resources)
166
- Monarchy.hierarchy_class.where(resource: resources)
167
- end
168
-
169
162
  def descendants_for(resources)
170
- resources_hierarchies = hierarchies_for(resources).select(:id)
171
-
172
- Monarchy.hierarchy_class
173
- .joins('INNER JOIN monarchy_hierarchy_hierarchies ON ' \
174
- 'monarchy_hierarchies.id = monarchy_hierarchy_hierarchies.descendant_id')
175
- .where(monarchy_hierarchy_hierarchies: { ancestor_id: resources_hierarchies })
176
- .where.not(monarchy_hierarchies: { id: resources_hierarchies })
163
+ resources_hierarchies = Monarchy.hierarchy_class.hierarchies_for(resources).select(:id)
164
+ Monarchy.hierarchy_class.descendants_for(resources_hierarchies)
177
165
  end
178
166
 
179
167
  def ancestors_for(resources)
180
- resources_hierarchies = hierarchies_for(resources).select(:id)
181
-
182
- Monarchy.hierarchy_class
183
- .joins('INNER JOIN monarchy_hierarchy_hierarchies ON ' \
184
- 'monarchy_hierarchies.id = monarchy_hierarchy_hierarchies.ancestor_id')
185
- .where(monarchy_hierarchy_hierarchies: { descendant_id: resources_hierarchies })
186
- .where.not(monarchy_hierarchies: { id: resources_hierarchies })
168
+ resources_hierarchies = Monarchy.hierarchy_class.hierarchies_for(resources).select(:id)
169
+ Monarchy.hierarchy_class.ancestors_for(resources_hierarchies)
187
170
  end
188
171
  end
189
172
  end
@@ -44,16 +44,6 @@ module Monarchy
44
44
  end
45
45
  end
46
46
 
47
- class ModelNotHierarchy < Error
48
- def initialize(resource)
49
- @resource = resource
50
- end
51
-
52
- def message
53
- "Model '#{@resource.class}' is not a hierarchy!"
54
- end
55
- end
56
-
57
47
  class ModelNotMember < Error
58
48
  def initialize(member)
59
49
  @member = member
@@ -97,12 +87,6 @@ module Monarchy
97
87
  end
98
88
  end
99
89
 
100
- class HierarchyIsNil < Error
101
- def message
102
- 'Hierarchy can NOT be nil!'
103
- end
104
- end
105
-
106
90
  class UserIsNil < Error
107
91
  def message
108
92
  'User can NOT be nil!'
@@ -126,11 +110,5 @@ module Monarchy
126
110
  'Resource has to persisted!'
127
111
  end
128
112
  end
129
-
130
- class HierarchyNotPersist < Error
131
- def message
132
- 'Resource has to persisted!'
133
- end
134
- end
135
113
  end
136
114
  end
@@ -39,16 +39,6 @@ module Monarchy
39
39
  persistance && resource && !resource.persisted? ? raise(Monarchy::Exceptions::ResourceNotPersist) : model
40
40
  end
41
41
 
42
- def hierarchy(hierarchy, allow_nil = false, persistance = true)
43
- raise Monarchy::Exceptions::HierarchyIsNil if !hierarchy && !allow_nil
44
-
45
- model = check_model_class(hierarchy, 'ModelNotHierarchy') do
46
- hierarchy.is_a?(Monarchy.hierarchy_class)
47
- end
48
-
49
- persistance && hierarchy && !hierarchy.persisted? ? raise(Monarchy::Exceptions::HierarchyNotPersist) : model
50
- end
51
-
52
42
  def user(user, allow_nil = false)
53
43
  raise Monarchy::Exceptions::UserIsNil if !user && !allow_nil
54
44
  model_is_class(user, Monarchy.user_class, 'ModelNotUser')
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Monarchy
4
- VERSION = '2.2.2'
4
+ VERSION = '2.3.0'
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: monarchy
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.2.2
4
+ version: 2.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Exelord