klastera 1.2.2 → 1.2.4.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5ca95ff5ffe21289a12131f7090036072103e196af1d81f9110c7896d705f837
4
- data.tar.gz: c026cb690ec0fdbad89237a64e837b74e5112c50b4339dc78e3bdce03dfd84d5
3
+ metadata.gz: 8780a6928f5249deb34be42cac1f52a226113865b9f29ddb12e1a36f018141ed
4
+ data.tar.gz: 1d99b709cea49a08533192ad8a1df621d78ea4d4ee59e1c266f06e952e6d8063
5
5
  SHA512:
6
- metadata.gz: 1f71455ad531a02b1f46672644f8d77aa98a4c842121de8fa1539e26920690d103e997a22470ea5dfa0efdbce6a970a89a824324343b87d90546aa4ad3653e5b
7
- data.tar.gz: 1d5962c2c598cc389c67306fcd8bbf10ca7577c07bc89795daf98d774537bac01ddcdbd366c2478a4cfc0ea3b3b9082dd1c20edcf0e58e481d7461b92c71c372
6
+ metadata.gz: 62c72441e00d9edb6c17525453cde71d864389c9342dbe54df3538609814aef0cdcbc3f7c49f49134d526e2da1f99ff1cc258b750cd024a7031afd3a80977d2d
7
+ data.tar.gz: 806978a3fae34b0a2ddda331ce37b90de2e66f9c77bd707859b721ac7c83980f706b5eb432a00875db8b26b4c8901b11307ef62ab063952d013eef30eca69772
@@ -9,9 +9,10 @@ module Klastera::Concerns::Clusterizable
9
9
 
10
10
  validates :cluster_id, presence: true, if: proc { self.try(:cluster_id) && self.organization.required_suborganization_mode? }
11
11
  validate :at_least_one_cluster_entity, if: proc { self.organization.required_suborganization_mode? }
12
+ validate :uniqueness_of_cluster_entity_record
12
13
 
13
14
  scope :related_clusters, ->() {
14
- includes(:cluster_entities).where("cluster_entities.entity_id = #{self.table_name}.id")
15
+ joins(:cluster_entities).where("cluster_entities.entity_id = #{self.table_name}.id")
15
16
  }
16
17
 
17
18
  def at_least_one_cluster_entity
@@ -20,8 +21,15 @@ module Klastera::Concerns::Clusterizable
20
21
  end
21
22
  end
22
23
 
24
+ ##
25
+ # This is a legacy method and we don't recommend using it.
26
+ # Implement directly Klastera.entity_clusters_string_list instead of this method.
27
+ # TODO: In order to deprecate it, you will need to perform some changes in the main app
28
+ ##
23
29
  def clusters_string_separated_by(separator,attribute=:name)
24
- self.cluster_entities.map{|ce|ce.cluster.send(attribute)}.join(separator)
30
+ Klastera.entity_clusters_string_list!(
31
+ self.cluster_entities, separator, attribute
32
+ )
25
33
  end
26
34
 
27
35
  def has_one_cluster_entity
@@ -29,6 +37,12 @@ module Klastera::Concerns::Clusterizable
29
37
  return errors.add(:cluster_entities, I18n.t('klastera.messages.has_one_cluster_entity'))
30
38
  end
31
39
  end
40
+
41
+ def uniqueness_of_cluster_entity_record
42
+ if cluster_entities.map(&:cluster_id).uniq.size != cluster_entities.size
43
+ return errors.add(:cluster_entities, I18n.t('klastera.messages.duplicated_cluster_entity') )
44
+ end
45
+ end
32
46
  end
33
47
 
34
48
  module ClassMethods
@@ -1,6 +1,6 @@
1
1
  <tr class="nested-fields">
2
2
  <td class="field">
3
- <%= f.select :cluster_id, cluster_clusters.map{|c|[c.name,c.id]}, { include_blank: true }, { class: 'form-control' } %>
3
+ <%= f.select :cluster_id, @cluster_clusters.map{|c|[c.name,c.id]}, { include_blank: true }, { class: 'form-control' } %>
4
4
  </td>
5
5
  <td class="action vertical-align-middle text-center" width="44">
6
6
  <%= link_to_remove_association f, class: 'btn btn-danger btn-xs text-danger' do %>
@@ -1,4 +1,5 @@
1
1
  <% if cluster_organization.is_in_cluster_mode? %>
2
+ <% @cluster_clusters = cluster_clusters %>
2
3
  <div class="col-xs-12">
3
4
  <% if hide_title||=false %>
4
5
  <div class="form-group file required <%=f.object.class.name.parameterize%>_cluster_entity<%=' has-error' if f.object.errors.has_key?(:cluster_entities)%>">
@@ -26,6 +27,7 @@
26
27
  <table id="cluster-entities" class="table table-striped">
27
28
  <tbody class="cluster-entity-rows">
28
29
  <%= f.fields_for :cluster_entities do |cluster_entity|%>
30
+ <% next unless @cluster_clusters.map(&:id).include?(cluster_entity.try(:object).try(:cluster_id)) %>
29
31
  <%= render 'layouts/klastera/cluster_entity_fields', f: cluster_entity %>
30
32
  <% end %>
31
33
  </body>
@@ -61,6 +61,7 @@ es:
61
61
  at_least_one_cluster_entity: Debe agregar al menos un cluster
62
62
  record_action_successfully: Registro %{a} exitosamente
63
63
  cant_delete_the_last_record_in_required_suborganization_mode: No se puede eliminar el único cluster de esta organización
64
+ duplicated_cluster_entity: Hay un cluster duplicado
64
65
  new_cluster_id:
65
66
  nil: Cluster no existe
66
67
  same: Cluster no puede ser el mismo
@@ -5,6 +5,12 @@ module Klastera
5
5
 
6
6
  extend ActiveSupport::Concern
7
7
 
8
+ KLSTR_HELPERS = %i[
9
+ cluster_user cluster_organization user_has_more_than_one_cluster
10
+ cluster_scope cluster_clusters cluster_scope_filtered clusters_from
11
+ user_clusters_string_list set_collection_before_group_by_entity
12
+ ]
13
+
8
14
  class << self
9
15
 
10
16
  def set_cluster_entities_attributes!(entity,array_cluster_ids)
@@ -30,13 +36,15 @@ module Klastera
30
36
  end
31
37
 
32
38
  #
33
- # I like to wrap methods
39
+ # In cases you don't have the active_record_collection object to filter, this method helps you
40
+ # calling cluster_scope! before and pass the collction to filter_clusterized_collection_with!,
41
+ # but at the end of the day, I just like to wrap methods.
34
42
  #
35
- def cluster_scope_filtered!(scope,cluster_id,user,organization,includes=[])
43
+ def cluster_scope_filtered!(scope,cluster_id,user,organization)
36
44
  self.filter_clusterized_collection_with!(
37
- organization,
38
45
  cluster_id,
39
- self.cluster_scope!(user,organization,scope,includes)
46
+ self.cluster_scope!(scope,user,organization),
47
+ organization
40
48
  )
41
49
  end
42
50
 
@@ -44,74 +52,88 @@ module Klastera
44
52
  # In order to this works, active_record_collection argument
45
53
  # should be passed through cluster_scope! method before.
46
54
  #
47
- def filter_clusterized_collection_with!(cluster_organization,cluster_id,active_record_collection)
55
+ def filter_clusterized_collection_with!(cluster_id,active_record_collection,cluster_organization)
48
56
  if cluster_organization.is_in_cluster_mode?
57
+
58
+ # IMPORTANT
59
+ # The next block was commented on because cluster_scope! method is not returning
60
+ # the cluster_entities within the scope anymore and it doesn't make any sense trying
61
+ # to filter based on force/use/show logic. Nevertheless, someday we will need it again.
62
+
63
+ # # If cluster_id is nil we will try to filter including unclustered entities active_record_collection wsas
64
+ # unless cluster_id.present?
65
+ # # Based on force/use/show definition we don't really need this validation. A force cluster organization won't return an entity that
66
+ # # doesn't belong to a cluster. Nevertheless we don't know if active_record_collection argument is fully definition-compliant.
67
+ # if cluster_organization.optional_suborganization_mode?
68
+ # cluster_array << nil
69
+ # end
70
+ # end
71
+
49
72
  if cluster_id.present?
50
- cluster_array = [cluster_id]
51
- # Based on force/use/show definition we don't really need this validation.
52
- # A force cluster organization won't return an entity out of a cluster, but
53
- # we don't know if the clusterized entities are fully definition-compliant.
54
- cluster_array << nil if cluster_organization.optional_suborganization_mode?
73
+ cluster_array = [cluster_id] unless cluster_id.is_a?(Array)
74
+ # The ActiveRecordCollection argument should have previously eager-loaded the cluster entities, thus the join statement is unnecessary.
55
75
  active_record_collection = active_record_collection.joins(:cluster_entities).where("cluster_entities.cluster_id": cluster_array)
56
76
  end
57
- # you may use a block only with clusterizable data
77
+
78
+ # You should use a block with clusterable data only
58
79
  yield(active_record_collection) if block_given?
59
80
  end
60
81
  active_record_collection
61
82
  end
62
83
 
63
- #
64
- #
65
- #
66
- def set_collection_before_group_by_entity!(cluster_organization,active_record_collection,model_class,entity_params)
84
+ ##
85
+ #
86
+ #
87
+ ##
88
+ def set_collection_before_group_by_entity!(active_record_collection,entity_params,cluster_organization)
67
89
  entity_params_keys = [:entity_name,:entity_attribute,:entity_id,:entity_id_attribute,:unamed]
90
+ entity_params[:entity_id] ||= nil #Ensures the entity_id attribute presence even if there is no filter
68
91
  entity_params = entity_params.slice(*entity_params_keys).values
69
- if model_class.try(:reflections).try(:keys).try(:include?,entity_params[0])
92
+ model_class = active_record_collection.model.base_class
93
+ model_relations = model_class.reflections.keys
94
+ if model_relations.include?(entity_params[0])
70
95
  entity_params << "#{entity_params[0]}_id".to_sym
71
96
  if entity_params[0] == 'cluster'
72
97
  entity_params << :unclustered if cluster_organization.is_in_cluster_mode?
73
98
  active_record_collection = Klastera.filter_clusterized_collection_with!(
74
- cluster_organization,
75
99
  entity_params[2],
76
- active_record_collection
100
+ active_record_collection,
101
+ cluster_organization
77
102
  )
78
103
  end
79
- yield(
80
- active_record_collection,
81
- entity_params_keys.zip(entity_params).to_h)
104
+ yield( active_record_collection, entity_params_keys.zip(entity_params).to_h )
82
105
  end
83
106
  end
84
107
 
85
108
  ##
86
109
  # Returns a ::Cluster::ActiveRecord_Relation from a given scope
87
110
  #
88
- def clusters_from!(user,organization,scope,includes=[])
89
- cluster_scope!(user,organization,scope,includes).related_clusters
111
+ def clusters_from!(scope,user,organization)
112
+ cluster_scope!(scope,user,organization).related_clusters
90
113
  end
91
114
 
92
115
  ##
93
116
  # Returns a scope filtered by clusters or its
94
117
  # organization if the cluster mode is not active.
95
118
  #
96
- def cluster_scope!(user,organization,scope,includes=[])
119
+ def cluster_scope!(scope,user,organization)
97
120
  scope_klass = scope_class(scope).where(organization_id: organization)
98
121
  session_clusters(user,organization) do |clusters|
99
122
  if organization.is_in_cluster_mode?
100
123
  scope_klass = scope_klass.select("DISTINCT ON (#{scope.table_name}.id) #{scope.table_name}.id, #{scope.table_name}.*")
101
- scope_klass = scope_klass.includes(includes) if includes.present?
102
124
  cluster_ids = clusters.map(&:id)
103
125
  if organization.required_suborganization_mode?
104
126
  scope_klass = scope_klass.joins(:cluster_entities).where( cluster_entities: { cluster_id: cluster_ids } )
105
127
  else
128
+ or_these_cluster_ids = cluster_ids.present? ? " OR cluster_entities.cluster_id IN (#{cluster_ids.join(",")})" : ""
106
129
  scope_klass = scope_klass.joins("
107
130
  LEFT OUTER JOIN cluster_entities
108
- ON cluster_entities.cluster_id IN (#{cluster_ids.join(",")})
109
- AND entity_id = #{scope.table_name}.id
131
+ ON entity_id = #{scope.table_name}.id
110
132
  AND entity_type = '#{scope}'
111
- ")
133
+ ").where("cluster_entities.id IS NULL#{or_these_cluster_ids}")
112
134
  end
113
135
  # Provisional fix to avoid SQL clashes due to DISTINCT ON clause
114
- scope_klass = scope_class(scope).where(organization_id: organization).where(id: scope_klass.map(&:id))
136
+ scope_klass = scope_class(scope).eager_load(:cluster_entities).where(id: scope_klass.map(&:id), organization_id: organization)
115
137
  end
116
138
  end
117
139
  scope_klass
@@ -143,38 +165,42 @@ module Klastera
143
165
  end
144
166
  clusters
145
167
  end
146
- end
147
168
 
148
- included do
149
- if respond_to?(:helper_method)
150
- helper_method :cluster_scope
151
- helper_method :user_cluster
152
- helper_method :cluster_user
153
- helper_method :cluster_organization
154
- helper_method :cluster_clusters
155
- helper_method :cluster_scope_filtered
156
- helper_method :user_has_more_than_one_cluster
157
- helper_method :clusters_from
169
+ ##
170
+ # Return a string with cluster attribute separated by separator argument
171
+ # A array of cluster ids can be passed fo filter the result
172
+ #
173
+ def entity_clusters_string_list!(cluster_entities,separator,attribute=:name,allowed_cluster_ids=nil)
174
+ _cluster_entities = cluster_entities.reject(&:nil?)
175
+ if allowed_cluster_ids.is_a?(Array)
176
+ _cluster_entities.select!{|ce| allowed_cluster_ids.include?(ce.cluster_id)}
177
+ end
178
+ _cluster_entities.map do |ce|
179
+ ce.cluster.try(attribute)
180
+ end.compact.join(separator)
158
181
  end
159
- if respond_to?(:hide_action)
160
- hide_action :cluster_scope
161
- hide_action :cluster_scope=
162
- hide_action :user_cluster
163
- hide_action :user_cluster=
164
- hide_action :cluster_user
165
- hide_action :cluster_user=
166
- hide_action :cluster_organization
167
- hide_action :cluster_organization=
168
- hide_action :cluster_clusters
169
- hide_action :cluster_clusters=
170
- hide_action :cluster_scope_filtered
171
- hide_action :cluster_scope_filtered=
172
- hide_action :user_has_more_than_one_cluster
173
- hide_action :user_has_more_than_one_cluster=
174
- hide_action :clusters_from
175
- hide_action :clusters_from=
182
+
183
+ ##
184
+ # cluster_clusters needs the logged user and its organization
185
+ # that why, we perfomed this logic here
186
+ #
187
+ def user_clusters_string_list!(user,organization,cluster_entities,separator,attribute=:name)
188
+ @_session_clusters ||= self.session_clusters(user,organization)
189
+ self.entity_clusters_string_list!(cluster_entities, separator, attribute, @_session_clusters.map(&:id))
176
190
  end
177
- before_action :set_the_lonely_cluster, only: %i[ create update ]
191
+ end
192
+
193
+ def cluster_user
194
+ current_user
195
+ end
196
+
197
+ def cluster_organization
198
+ current_organization
199
+ end
200
+
201
+ def user_has_more_than_one_cluster
202
+ @cluster_clusters ||= cluster_clusters
203
+ @cluster_clusters.size > 1
178
204
  end
179
205
 
180
206
  def set_the_lonely_cluster
@@ -186,52 +212,69 @@ module Klastera
186
212
  end
187
213
  end
188
214
 
189
- def cluster_scope(scope,includes=[])
190
- Klastera.cluster_scope!(cluster_user,cluster_organization,scope,includes)
215
+ def set_cluster_filter
216
+ @filter = ::ClusterFilter.new(cluster_filter_params)
217
+ end
218
+
219
+ def cluster_filter_params
220
+ parameters = params.require(:cluster_filter) rescue nil
221
+ return {} if parameters.blank?
222
+ parameters.permit(*cluster_filter_permit_params)
191
223
  end
192
224
 
193
- def cluster_user
194
- current_user
225
+ def cluster_filter_permit_params
226
+ [ :cluster_id ].concat( ::ClusterFilter.attributes )
195
227
  end
196
228
 
197
- def cluster_organization
198
- current_organization
229
+ def filter_clusterized_collection_with(cluster_id,active_record_collection)
230
+ Klastera.filter_clusterized_collection_with!(cluster_id,active_record_collection,cluster_organization)
231
+ end
232
+
233
+ def cluster_scope(scope)
234
+ Klastera.cluster_scope!(scope,cluster_user,cluster_organization)
199
235
  end
200
236
 
201
237
  def cluster_clusters
202
238
  Klastera.session_clusters(cluster_user,cluster_organization)
203
239
  end
204
240
 
205
- def cluster_scope_filtered(scope,cluster_id,includes=[])
241
+ def cluster_scope_filtered(scope,cluster_id)
206
242
  Klastera.cluster_scope_filtered!(
207
243
  scope,
208
244
  cluster_id,
209
245
  cluster_user,
210
- cluster_organization,
211
- includes
246
+ cluster_organization
212
247
  )
213
248
  end
214
249
 
215
- def user_has_more_than_one_cluster
216
- @cluster_clusters ||= cluster_clusters
217
- @cluster_clusters.size > 1
218
- end
219
-
220
- def clusters_from(scope,includes=[])
221
- Klastera.clusters_from!(cluster_user,cluster_organization,scope,includes)
250
+ def clusters_from(scope)
251
+ Klastera.clusters_from!(scope,cluster_user,cluster_organization)
222
252
  end
223
253
 
224
- def set_cluster_filter
225
- @filter = ::ClusterFilter.new(cluster_filter_params)
254
+ def user_clusters_string_list(object_entity,separator,attribute=:name)
255
+ Klastera.user_clusters_string_list!(
256
+ cluster_user,
257
+ cluster_organization,
258
+ object_entity.try(:cluster_entities),
259
+ separator,
260
+ attribute
261
+ )
226
262
  end
227
263
 
228
- def cluster_filter_params
229
- parameters = params.require(:cluster_filter) rescue nil
230
- return {} if parameters.blank?
231
- parameters.permit(*cluster_filter_permit_params)
264
+ def set_collection_before_group_by_entity(active_record_collection,entity_params,&block)
265
+ Klastera.set_collection_before_group_by_entity!(active_record_collection,params,cluster_organization,&block)
232
266
  end
233
267
 
234
- def cluster_filter_permit_params
235
- [ :cluster_id ].concat( ::ClusterFilter.attributes )
268
+ included do
269
+ Klastera::KLSTR_HELPERS.each do |action|
270
+ if respond_to?(:helper_method)
271
+ helper_method(action)
272
+ end
273
+ if respond_to?(:hide_action)
274
+ hide_action(helper)
275
+ hide_action("#{helper}=")
276
+ end
277
+ end
278
+ before_action :set_the_lonely_cluster, only: %i[ create update ]
236
279
  end
237
280
  end
@@ -1,3 +1,3 @@
1
1
  module Klastera
2
- VERSION = "1.2.2"
3
- end
2
+ VERSION = "1.2.4.2"
3
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: klastera
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.2
4
+ version: 1.2.4.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Gino Barahona
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-06-05 00:00:00.000000000 Z
11
+ date: 2020-06-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -54,7 +54,6 @@ files:
54
54
  - app/controllers/klastera/application_controller.rb
55
55
  - app/controllers/klastera/clusters_controller.rb
56
56
  - app/helpers/klastera/application_helper.rb
57
- - app/helpers/klastera/clusters_helper.rb
58
57
  - app/models/klastera/cluster.rb
59
58
  - app/models/klastera/cluster_entity.rb
60
59
  - app/models/klastera/cluster_filter.rb
@@ -1,4 +0,0 @@
1
- module Klastera
2
- module ClustersHelper
3
- end
4
- end