klastera 1.5.4 → 1.5.5.1

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.
Files changed (66) hide show
  1. checksums.yaml +4 -4
  2. data/MIT-LICENSE +0 -0
  3. data/README.rdoc +0 -0
  4. data/Rakefile +0 -0
  5. data/app/assets/javascripts/klastera/application.js +0 -0
  6. data/app/assets/javascripts/klastera/clusters.js +0 -0
  7. data/app/assets/stylesheets/klastera/clusters.scss +0 -0
  8. data/app/controllers/klastera/application_controller.rb +0 -0
  9. data/app/controllers/klastera/clusters_controller.rb +0 -0
  10. data/app/helpers/klastera/application_helper.rb +0 -0
  11. data/app/models/klastera/cluster.rb +0 -0
  12. data/app/models/klastera/cluster_entity.rb +0 -0
  13. data/app/models/klastera/cluster_filter.rb +0 -0
  14. data/app/models/klastera/cluster_user.rb +0 -0
  15. data/app/models/klastera/concerns/cluster.rb +0 -0
  16. data/app/models/klastera/concerns/cluster_entity.rb +0 -0
  17. data/app/models/klastera/concerns/cluster_filter.rb +0 -0
  18. data/app/models/klastera/concerns/cluster_user.rb +0 -0
  19. data/app/models/klastera/concerns/clusterizable.rb +62 -4
  20. data/app/models/klastera/concerns/organization.rb +0 -0
  21. data/app/models/klastera/concerns/transfer.rb +0 -0
  22. data/app/models/klastera/concerns/user.rb +0 -0
  23. data/app/models/klastera/transfer.rb +0 -0
  24. data/app/views/klastera/clusters/_filter.html.erb +0 -0
  25. data/app/views/klastera/clusters/_form.html.erb +0 -0
  26. data/app/views/klastera/clusters/_form_transfer.html.erb +0 -0
  27. data/app/views/klastera/clusters/_table.html.erb +0 -0
  28. data/app/views/klastera/clusters/create.js.erb +0 -0
  29. data/app/views/klastera/clusters/destroy.js.erb +0 -0
  30. data/app/views/klastera/clusters/edit.html.erb +0 -0
  31. data/app/views/klastera/clusters/index.html.erb +0 -0
  32. data/app/views/klastera/clusters/new.html.erb +0 -0
  33. data/app/views/klastera/clusters/transfer.html.erb +0 -0
  34. data/app/views/klastera/clusters/update.js.erb +0 -0
  35. data/app/views/layouts/klastera/_cluster_entity_fields.html.erb +0 -0
  36. data/app/views/layouts/klastera/_cluster_filter.html.erb +0 -0
  37. data/app/views/layouts/klastera/_cluster_role.html.erb +0 -0
  38. data/app/views/layouts/klastera/_cluster_selector.html.erb +0 -0
  39. data/app/views/layouts/klastera/_cluster_user_fields.html.erb +0 -0
  40. data/app/views/layouts/klastera/_nested_cluster_entity.html.erb +0 -0
  41. data/app/views/layouts/klastera/_nested_cluster_user.html.erb +0 -0
  42. data/app/views/layouts/klastera/_options.html.erb +0 -0
  43. data/config/locales/es.yml +0 -0
  44. data/config/routes.rb +0 -0
  45. data/db/migrate/20200324203929_create_klastera_clusters.rb +0 -0
  46. data/db/migrate/20200326111219_add_cluster_options_to_organizations.rb +0 -0
  47. data/db/migrate/20200330010551_create_klastera_cluster_users.rb +0 -0
  48. data/db/migrate/20200330221601_add_order_field_to_clusters.rb +0 -0
  49. data/db/migrate/20200518142609_create_klastera_cluster_entities.rb +0 -0
  50. data/db/migrate/20200908180057_add_cluster_config_to_organization.rb +0 -0
  51. data/db/migrate/20220602222332_add_unique_index_to_cluster_entities.rb +0 -0
  52. data/db/migrate/20250429110829_add_entity_id_index_to_cluster_entities.rb +6 -0
  53. data/db/migrate/20250429110830_add_entity_id_index_and_entity_type_index_to_cluster_entities.klastera.rb +7 -0
  54. data/lib/klastera/engine.rb +0 -0
  55. data/lib/klastera/version.rb +1 -1
  56. data/lib/klastera.rb +36 -3
  57. data/lib/tasks/klastera_tasks.rake +0 -0
  58. data/test/controllers/klastera/clusters_controller_test.rb +0 -0
  59. data/test/fixtures/klastera/cluster_users.yml +0 -0
  60. data/test/fixtures/klastera/clusters.yml +0 -0
  61. data/test/integration/navigation_test.rb +0 -0
  62. data/test/klastera_test.rb +0 -0
  63. data/test/models/klastera/cluster_test.rb +0 -0
  64. data/test/models/klastera/cluster_user_test.rb +0 -0
  65. data/test/test_helper.rb +0 -0
  66. metadata +6 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b05f393fbe67e0822de3526d5b46dc7081a79226f45b5fe63985424d73331742
4
- data.tar.gz: '09623883ce4911b3cd0df6382c558c7d82f080eb504f3e0dae4e74262acd8df7'
3
+ metadata.gz: 01b3c7e4c25fc9bfa852d34304d0f0cb12b832da7565375eb9e4cb5f4abc2566
4
+ data.tar.gz: 5ccc41a05b2e0ae3a5e8f4b16176be63ec752b0a112f3d8c1276bd403b591386
5
5
  SHA512:
6
- metadata.gz: 9589942522f4442bf44304cb735a022819bb40f0885c077d77289791caf79f266a1f258d3db7f14fc242d0d80858a8c82027b0314f2faf5ef156e45bcf1c89a7
7
- data.tar.gz: 3b5d0a9505bd241d3374077ab01d8ddcd2ca83d3f4787763de1658c56f362680b3cb2350e44992a2041834181b7b379c5ad506d4ba83278d140ba6a7d6a775da
6
+ metadata.gz: 07c277261a1ff65e45ca4413587c3ca51952e497176d2a3e29e361c955a51e2d6d77bd4ae5ee8946e8981d56fa1ec756eed81b12e454f623732e5505a7a09349
7
+ data.tar.gz: 6f1097125134ab6a528c165df1396697c4c83db96bbfa2265b19f04025a2f72fe5a4e423dcf2a49f23fb0fcb75156911471190e332fae94cd962e2331d0042b7
data/MIT-LICENSE CHANGED
File without changes
data/README.rdoc CHANGED
File without changes
data/Rakefile CHANGED
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
@@ -14,6 +14,7 @@ module Klastera::Concerns::Clusterizable
14
14
  validate :uniqueness_of_cluster_entity_record
15
15
 
16
16
  scope :includes_cluster, -> { includes(cluster_entities: :cluster) }
17
+ scope :with_clusters, -> { includes(cluster_entities: :cluster) }
17
18
 
18
19
  def at_least_one_cluster_entity
19
20
  if cluster_entities.length == 0 || cluster_entities.reject{|cluster_entity| cluster_entity._destroy == true}.empty?
@@ -26,11 +27,24 @@ module Klastera::Concerns::Clusterizable
26
27
  end
27
28
 
28
29
  ##
29
- # This is a legacy method and we don't recommend using it.
30
- # Implement directly Klastera.entity_clusters_string_list instead of this method.
31
- # TODO: In order to deprecate it, you will need to perform some changes in the main app
30
+ # This method has been optimized to use preloaded associations when available
31
+ # Falls back to efficient single-query approach when associations aren't preloaded
32
32
  ##
33
- def clusters_string_separated_by(separator,attribute=:name)
33
+ def clusters_string_separated_by(separator, attribute=:name)
34
+ # Use Rails cache for frequently accessed cluster strings
35
+ cache_key = [self.cache_key_with_version, :clusters_string, separator, attribute]
36
+
37
+ Rails.cache.fetch(cache_key, expires_in: 30.minutes) do
38
+ Klastera.entity_clusters_string_list!(
39
+ cluster_entities, separator, attribute
40
+ )
41
+ end
42
+ end
43
+
44
+ ##
45
+ # Optimized version without cache for real-time updates
46
+ ##
47
+ def clusters_string_separated_by_uncached(separator, attribute=:name)
34
48
  Klastera.entity_clusters_string_list!(
35
49
  cluster_entities, separator, attribute
36
50
  )
@@ -53,5 +67,49 @@ module Klastera::Concerns::Clusterizable
53
67
  def cluster_entity_params
54
68
  [ :cluster_id, { cluster_entities_attributes: [:id, :cluster_id, :_destroy] } ]
55
69
  end
70
+
71
+ ##
72
+ # Efficiently preload clusters for a collection of entities
73
+ # This prevents N+1 queries when calling clusters_string_separated_by on multiple entities
74
+ ##
75
+ def preload_clusters(collection)
76
+ return collection if collection.empty?
77
+
78
+ ActiveRecord::Associations::Preloader.new.preload(
79
+ collection,
80
+ cluster_entities: :cluster
81
+ )
82
+ collection
83
+ end
84
+
85
+ ##
86
+ # Batch update cluster assignments for multiple entities
87
+ # More efficient than individual updates
88
+ ##
89
+ def batch_assign_clusters(entity_ids, cluster_ids)
90
+ return if entity_ids.empty? || cluster_ids.empty?
91
+
92
+ # Clear existing assignments
93
+ Klastera::ClusterEntity.where(
94
+ entity_type: self.name,
95
+ entity_id: entity_ids
96
+ ).destroy_all
97
+
98
+ # Create new assignments
99
+ cluster_assignments = []
100
+ entity_ids.each do |entity_id|
101
+ cluster_ids.each do |cluster_id|
102
+ cluster_assignments << {
103
+ entity_type: self.name,
104
+ entity_id: entity_id,
105
+ cluster_id: cluster_id,
106
+ created_at: Time.current,
107
+ updated_at: Time.current
108
+ }
109
+ end
110
+ end
111
+
112
+ Klastera::ClusterEntity.insert_all(cluster_assignments) if cluster_assignments.any?
113
+ end
56
114
  end
57
115
  end
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
data/config/routes.rb CHANGED
File without changes
@@ -0,0 +1,6 @@
1
+ class AddEntityIdIndexToClusterEntities < ActiveRecord::Migration[5.2]
2
+ disable_ddl_transaction!
3
+ def change
4
+ add_index :cluster_entities, :entity_id, algorithm: :concurrently
5
+ end
6
+ end
@@ -0,0 +1,7 @@
1
+ # This migration comes from klastera (originally 20250429110947)
2
+ class AddEntityIdIndexAndEntityTypeIndexToClusterEntities < ActiveRecord::Migration[5.2]
3
+ disable_ddl_transaction!
4
+ def change
5
+ add_index :cluster_entities, [:entity_id,:entity_type], algorithm: :concurrently
6
+ end
7
+ end
File without changes
@@ -1,3 +1,3 @@
1
1
  module Klastera
2
- VERSION = "1.5.4"
2
+ VERSION = "1.5.5.1"
3
3
  end
data/lib/klastera.rb CHANGED
@@ -46,15 +46,48 @@ module Klastera
46
46
  ##
47
47
  # Return a string with cluster attribute separated by separator argument
48
48
  # A array of cluster ids can be passed fo filter the result
49
+ # Optimized version that uses preloaded associations when available
49
50
  #
50
51
  def entity_clusters_string_list!(cluster_entities,separator,attribute=:name,allowed_cluster_ids=nil)
51
52
  _cluster_entities = cluster_entities.reject(&:nil?)
52
53
  if allowed_cluster_ids.is_a?(Array)
53
54
  _cluster_entities.select!{|ce| allowed_cluster_ids.include?(ce.cluster_id)}
54
55
  end
55
- _cluster_entities.map do |ce|
56
- ce.cluster.try(attribute)
57
- end.compact.sort.join(separator)
56
+
57
+ # Performance optimization: Use preloaded data when available
58
+ if cluster_entities.respond_to?(:loaded?) && cluster_entities.loaded? &&
59
+ _cluster_entities.all? { |ce| ce.association(:cluster).loaded? }
60
+ # Use in-memory data (much faster)
61
+ _cluster_entities.map do |ce|
62
+ ce.cluster.try(attribute)
63
+ end.compact.sort.join(separator)
64
+ else
65
+ # Fallback to original method with database query
66
+ # But use a single query instead of N+1
67
+
68
+ cluster_ids = _cluster_entities.filter_map(&:cluster_id).uniq
69
+ return "" if cluster_ids.empty?
70
+
71
+ records = ::Cluster.where(id: cluster_ids).pluck(:id, attribute)
72
+ return "" if records.empty?
73
+
74
+ # clusters_hash = if records.any? && !records.first.is_a?(Array)
75
+ # records.map { |id| [id, id] }.to_h
76
+ # else
77
+ # records.to_h
78
+ # end
79
+ # _cluster_entities.map do |ce|
80
+ # clusters_hash[ce.cluster_id]
81
+ # end.compact.sort.join(separator)
82
+
83
+ clusters_hash = records.first.is_a?(Array) ? records.to_h : records.index_by(&:itself)
84
+ _cluster_entities
85
+ .filter_map { |entity| clusters_hash[entity.cluster_id] }
86
+ .uniq
87
+ .sort
88
+ .join(separator)
89
+
90
+ end
58
91
  end
59
92
 
60
93
  ##
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
data/test/test_helper.rb CHANGED
File without changes
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.5.4
4
+ version: 1.5.5.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Gino Barahona
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-09-12 00:00:00.000000000 Z
11
+ date: 2025-06-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: 7.1.3.2
19
+ version: 5.2.6
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: 7.1.3.2
26
+ version: 5.2.6
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: pg
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -95,6 +95,8 @@ files:
95
95
  - db/migrate/20200518142609_create_klastera_cluster_entities.rb
96
96
  - db/migrate/20200908180057_add_cluster_config_to_organization.rb
97
97
  - db/migrate/20220602222332_add_unique_index_to_cluster_entities.rb
98
+ - db/migrate/20250429110829_add_entity_id_index_to_cluster_entities.rb
99
+ - db/migrate/20250429110830_add_entity_id_index_and_entity_type_index_to_cluster_entities.klastera.rb
98
100
  - lib/klastera.rb
99
101
  - lib/klastera/engine.rb
100
102
  - lib/klastera/version.rb