monarchy 2.2.2 → 2.3.0

Sign up to get free protection for your applications and to get access to all the features.
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