klastera 1.2.4.2 → 1.4

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: 8780a6928f5249deb34be42cac1f52a226113865b9f29ddb12e1a36f018141ed
4
- data.tar.gz: 1d99b709cea49a08533192ad8a1df621d78ea4d4ee59e1c266f06e952e6d8063
3
+ metadata.gz: ef7788eb1826bb5f7ee15fe495ee69f181d3c028b4e51250bee6adfe8be4acbc
4
+ data.tar.gz: d703b16d95ef2704ad7fcc01ed7d578f957744e362c2c968edea434eb97c167e
5
5
  SHA512:
6
- metadata.gz: 62c72441e00d9edb6c17525453cde71d864389c9342dbe54df3538609814aef0cdcbc3f7c49f49134d526e2da1f99ff1cc258b750cd024a7031afd3a80977d2d
7
- data.tar.gz: 806978a3fae34b0a2ddda331ce37b90de2e66f9c77bd707859b721ac7c83980f706b5eb432a00875db8b26b4c8901b11307ef62ab063952d013eef30eca69772
6
+ metadata.gz: 3927e49fb28dceb261c9400a214f7a84a074e2330425eada935086023e235c25c8c6b530c109a46b6c934a22183200669c2afd7ac481a7090c5249b9580b55d1
7
+ data.tar.gz: 8d812d8f464d26c10c4b97dfcbbcecf03d0ec62171269da18452e75aa91b88d71224300065b5b8b93a5c0c1af319ba008a9f3e600639bb881df42d4b2cb9c4f5
@@ -8,4 +8,39 @@
8
8
  background: none;
9
9
  }
10
10
  }
11
- }
11
+ }
12
+
13
+ #cluster-remote-table {
14
+ .cluster-id { width: 70px; }
15
+ .cluster-order { width: 70px; }
16
+ .cluster-color { width: 70px; }
17
+ .odd .colorless { color: #F9F9F9 }
18
+ .even .colorless { color: #FFF }
19
+ tr:hover .colorless { color: #444; opacity: 0.2;}
20
+ }
21
+
22
+ #cluster-remote-form {
23
+ h4.blank-modal-title {
24
+ margin: 0;
25
+ line-height: 28px;
26
+ letter-spacing: 0.05rem;
27
+ font-size: 21px;
28
+ font-weight: 400;
29
+ color: #666;
30
+ }
31
+ }
32
+
33
+
34
+ ul.klastera-option-help {
35
+ padding-left: 20px;
36
+ list-style-type: disc;
37
+ }
38
+
39
+ ul.klastera-option-help li {
40
+ margin-bottom: 10px;
41
+ padding-bottom: 5px;
42
+ border-bottom: 1px solid #DDD;
43
+ }
44
+
45
+ ul.klastera-option-help li b { color: #8A8A8A; font-weight: 400; }
46
+ ul.klastera-option-help li b:first-child { color: #2E5F9B; font-weight: bold; }
@@ -33,13 +33,11 @@ module Klastera
33
33
 
34
34
  def destroy
35
35
  new_cluster_id = params.require(:transfer).permit(:new_cluster_id).values.first rescue nil
36
- @transfer = Transfer.new(
37
- current_cluster: @cluster,
38
- new_cluster_id: new_cluster_id
39
- )
36
+ @transfer = Transfer.new( current_cluster: @cluster, new_cluster_id: new_cluster_id )
40
37
  if @transfer.valid?
41
- @transfer.to!(::Cluster.related_entities.map{|re|re.constantize})
42
- @cluster.destroy
38
+ if @transfer.apply!
39
+ @cluster.destroy
40
+ end
43
41
  set_clusters
44
42
  end
45
43
  end
@@ -8,9 +8,13 @@ module Klastera::Concerns::Cluster
8
8
 
9
9
  attr_reader :last_record
10
10
 
11
- MODES = [ :required_suborganization, :optional_suborganization, :optional_filter ].freeze
11
+ REQUIRED_MODE = :required_suborganization.freeze
12
+ OPTIONAL_MODE = :optional_suborganization.freeze
13
+ MODES = [ REQUIRED_MODE, OPTIONAL_MODE ].freeze
12
14
 
13
15
  belongs_to :organization, class_name: Klastera.organization_class
16
+ has_many :cluster_users
17
+ has_many :cluster_entities, dependent: :destroy
14
18
 
15
19
  scope :of, -> (organization,except_ids=[]) {
16
20
  _scope = where(organization: organization)
@@ -41,7 +45,7 @@ module Klastera::Concerns::Cluster
41
45
  end
42
46
 
43
47
  def has_related_entities_using_it?
44
- ::Cluster.total_records_assign_to(self) > 0
48
+ self.cluster_entities.size > 0
45
49
  end
46
50
 
47
51
  def can_transfer_and_destroy?
@@ -54,29 +58,10 @@ module Klastera::Concerns::Cluster
54
58
  end
55
59
 
56
60
  def display_name_nid
57
- "#{name} (#{nid})"
61
+ "#{name} (#{nid==Klastera::UNCLUSTERED_ENTITY ? I18n.t("klastera.#{ Klastera::UNCLUSTERED_ENTITY}") : nid})"
58
62
  end
59
63
  end
60
64
 
61
65
  module ClassMethods
62
- def related_entities(attr_needed: :class_name, macro: :has_many)
63
- ::Cluster.reflections.map do |association_name, reflection|
64
- reflection.send(attr_needed) if reflection.macro == macro
65
- end.compact
66
- end
67
-
68
- def total_records_assign_to(cluster_instance)
69
- related_entities(attr_needed: :name).inject(0) do |total, association_name|
70
- entity = cluster_instance.send(association_name)
71
- if entity.respond_to?(:cluster_id)
72
- total+=entity.where(cluster_id: cluster_instance.id).count
73
- end
74
- total
75
- end
76
- end
77
-
78
- def modes_as_strings
79
- ::Cluster::MODES.map{|m|m.to_s}
80
- end
81
66
  end
82
67
  end
@@ -4,11 +4,8 @@ module Klastera::Concerns::ClusterFilter
4
4
  included do
5
5
  include ActiveModel::Model
6
6
  include ActiveModel::Validations::Callbacks
7
- attr_accessor :cluster_id
8
7
 
9
- def kcluster_id
10
- self.cluster_id == 'without_cluster' ? nil : self.cluster_id
11
- end
8
+ attr_accessor :cluster_id
12
9
  end
13
10
 
14
11
  module ClassMethods
@@ -3,55 +3,39 @@ module Klastera::Concerns::ClusterUser
3
3
 
4
4
  included do
5
5
  self.table_name = 'cluster_users'
6
-
7
6
  belongs_to :user
8
7
  belongs_to :cluster
9
-
10
8
  validates :cluster_id, presence: true
11
-
12
- scope :of, -> (user,organization) {
13
- Rails.logger.warn("DON'T USE THIS SCOPE DIRECTLY: Use ::ClusterUser.clusters_from class method instead!")
14
- includes(:cluster).where(user_id: user, "clusters.organization_id": organization)
15
- }
16
9
  end
17
10
 
18
11
  module ClassMethods
12
+ ##
13
+ # Return a Cluster::ActiveRecord_Relation of organization (and) user
14
+ #
15
+ def clusters_of(organization,and_user=nil)
16
+ and_user_id = and_user.present? ? { users: { id: and_user } } : {}
17
+ ::Cluster.eager_load(cluster_users: :user).where({ organization_id: organization }.merge(and_user_id) )
18
+ end
19
19
 
20
20
  ##
21
- # Returns a hash with the users with cluster relation
22
- #
23
- def user_clusters_from(organization)
24
- users_hash = {}
25
- organization_cluster_ids = ::Cluster.of(organization).map(&:id)
26
- ::ClusterUser.includes(:user).where(cluster_id: organization_cluster_ids).each do |cluster_user|
27
- user_id = cluster_user.user_id || :uncluster
28
- users_hash[user_id] ||= []
29
- users_hash[user_id] << cluster_user.cluster_id
30
- end
31
- users_hash
21
+ # Return a User::ActiveRecord_Relation of organization (and) user
22
+ #
23
+ def users_of(organization)
24
+ ::User.eager_load(:cluster_users).where(users: { organization_id: organization } )
32
25
  end
33
26
 
34
27
  ##
35
- # Returns a Cluster::ActiveRecord_Relation
28
+ # Return a hash of users and its clusters
36
29
  #
37
- ##
38
- def clusters_from(user,organization)
39
- clusters = []
40
- unless user.can_admin_clusters?
41
- # We could return cu.clusters but you may quering this result and a array can't handle order, where and etc.
42
- # So we take only the cluster_ids and perfome a new search in order to get a Cluster::ActiveRecord_Relation
43
- # like the else block.
44
- # TODO: resolve it without quering twice
45
- clusters_id = ::ClusterUser.of(user,organization).map(&:cluster_id)
46
- clusters = ::Cluster.where(id: clusters_id)
47
- # Add a empty cluster instance to handle models without a cluster assignation. Only for use and show modes
48
- if organization.optional_mode?
49
- clusters << ::Cluster.new({nid: :without_cluster, name: I18n.t('klastera.without_cluster')})
50
- end
51
- else
52
- clusters = ::Cluster.of(organization)
30
+ def users_hash_of(organization)
31
+ users = {}
32
+ rows = self.users_of(organization).pluck("users.id AS user_id","cluster_users.cluster_id").uniq
33
+ rows.each do |row|
34
+ user_id = row.first
35
+ users[user_id] ||= []
36
+ users[user_id] << row.last
53
37
  end
54
- clusters
38
+ users
55
39
  end
56
40
  end
57
41
  end
@@ -1,7 +1,6 @@
1
1
  module Klastera::Concerns::Clusterizable
2
2
  extend ActiveSupport::Concern
3
3
  included do
4
- attr_accessor :lonely_cluster
5
4
  belongs_to :cluster
6
5
 
7
6
  has_many :cluster_entities, as: :entity, class_name: Klastera::ClusterEntity
@@ -11,9 +10,7 @@ module Klastera::Concerns::Clusterizable
11
10
  validate :at_least_one_cluster_entity, if: proc { self.organization.required_suborganization_mode? }
12
11
  validate :uniqueness_of_cluster_entity_record
13
12
 
14
- scope :related_clusters, ->() {
15
- joins(:cluster_entities).where("cluster_entities.entity_id = #{self.table_name}.id")
16
- }
13
+ scope :includes_cluster, -> { includes(cluster_entities: :cluster) }
17
14
 
18
15
  def at_least_one_cluster_entity
19
16
  if cluster_entities.length == 0 || cluster_entities.reject{|cluster_entity| cluster_entity._destroy == true}.empty?
@@ -47,7 +44,7 @@ module Klastera::Concerns::Clusterizable
47
44
 
48
45
  module ClassMethods
49
46
  def cluster_entity_params
50
- [ :cluster_id, :lonely_cluster, { cluster_entities_attributes: [:id, :cluster_id, :_destroy] } ]
47
+ [ :cluster_id, { cluster_entities_attributes: [:id, :cluster_id, :_destroy] } ]
51
48
  end
52
49
  end
53
50
  end
@@ -4,7 +4,7 @@ module Klastera::Concerns::Organization
4
4
 
5
5
  has_many :clusters
6
6
 
7
- validates :use_cluster_as, inclusion: { in: ::Cluster.modes_as_strings , message: I18n.t('klastera.clusters.wrong_option') }, if: proc{ use_cluster_as.present? }
7
+ validates :use_cluster_as, inclusion: { in: ::Cluster::MODES.map{|m|m.to_s}, message: I18n.t('klastera.clusters.wrong_option') }, if: proc{ use_cluster_as.present? }
8
8
 
9
9
  # Return a symbol version of use_cluster_as value
10
10
  def cluster_mode
@@ -22,19 +22,11 @@ module Klastera::Concerns::Organization
22
22
  end
23
23
 
24
24
  def required_suborganization_mode?
25
- cluster_mode == ::Cluster::MODES.first
25
+ cluster_mode == ::Cluster::REQUIRED_MODE
26
26
  end
27
27
 
28
28
  def optional_suborganization_mode?
29
- cluster_mode == ::Cluster::MODES.second
30
- end
31
-
32
- def optional_filter_mode?
33
- cluster_mode == ::Cluster::MODES.third
34
- end
35
-
36
- def optional_mode?
37
- optional_suborganization_mode? || optional_filter_mode?
29
+ cluster_mode == ::Cluster::OPTIONAL_MODE
38
30
  end
39
31
  end
40
32
 
@@ -7,20 +7,14 @@ module Klastera::Concerns::Transfer
7
7
  include ActiveModel::Model
8
8
  include ActiveModel::Validations::Callbacks
9
9
 
10
- attr_accessor :current_cluster, :new_cluster_id, :entities_transfered
10
+ attr_accessor :current_cluster, :new_cluster_id
11
11
 
12
12
  validates :current_cluster, presence: true
13
13
  validates :new_cluster_id, presence: true, if: proc { self.required_transfer? }
14
14
 
15
15
  validate do
16
16
  new_cluster = ::Cluster.find(self.new_cluster_id.to_i) rescue nil
17
- #
18
- # In my time, to_a? didnt work
19
- # current_cluster.class returned:
20
- # Cluster(id: integer, name: string, nid: text, organization_id: integer, created_at: datetime, updated_at: datetime, color: string)
21
- #
22
- # If you see this, please fixe it. Thanks
23
- #
17
+
24
18
  if current_cluster.class.name != 'Cluster' || current_cluster.try(:is_the_last_record_in_required_suborganization_mode?)
25
19
  errors.add(:current_cluster, I18n.t('klastera.messages.current_cluster.cant_transfer'))
26
20
  elsif self.required_transfer? && new_cluster_id.present? && new_cluster.nil?
@@ -33,22 +27,19 @@ module Klastera::Concerns::Transfer
33
27
  end
34
28
  end
35
29
 
36
- ##
37
- #
38
- #
39
- def to!(related_entities)
40
- self.entities_transfered = 0
41
- related_entities.each do |entity|
42
- if entity.is_a?(Class) && entity.respond_to?(:cluster_id)
43
- self.entities_transfered += entity.where(
44
- cluster_id: self.current_cluster.id
45
- ).update_all(cluster_id: self.new_cluster_id)
46
- end
47
- end
48
- end
49
-
50
30
  def required_transfer?
51
31
  self.current_cluster.required_transfer? && self.current_cluster.has_related_entities_using_it?
52
32
  end
33
+
34
+ ##
35
+ # A returned boolean is expected. It should always be true even nothing is
36
+ # transfered, and it only will return false if creation fails.
37
+ #
38
+ def apply!
39
+ Klastera::ClusterEntity.create(current_cluster.cluster_entities.map{ |relation|
40
+ next if self.new_cluster_id.blank?
41
+ { cluster_id: self.new_cluster_id, entity_id: relation.entity_id, entity_type: relation.entity_type }
42
+ }.compact)
43
+ end
53
44
  end
54
45
  end
@@ -21,10 +21,6 @@ module Klastera::Concerns::User
21
21
  def is_a_cluster_admin?; self.cluster_role == CLUSTER_ADMIN; end
22
22
  def is_a_cluster_user?; self.cluster_role == CLUSTER_USER; end
23
23
 
24
- def is_not_a_cluster_root?; ! self.is_a_cluster_root?; end
25
- def is_not_a_cluster_admin?; ! self.is_a_cluster_admin?; end
26
- def is_not_a_cluster_user?; ! self.is_a_cluster_user?; end
27
-
28
24
  def need_cluster_assignation?
29
25
  self.try(:organization).try(:required_suborganization_mode?) && self.is_a_cluster_user?
30
26
  end
@@ -33,6 +29,13 @@ module Klastera::Concerns::User
33
29
  self.organization.is_in_cluster_mode? && ( self.is_a_cluster_admin? || self.is_a_cluster_root? )
34
30
  end
35
31
 
32
+ #
33
+ # It tells if this user should see what they cluster role or organization dictates
34
+ # Adminers and users from show cluster modes skip cluster clause
35
+ def cannot_skip_cluster_clause?
36
+ ! ( self.is_a_cluster_admin? || self.is_a_cluster_root? || ( self.organization.optional_suborganization_mode? && self.cluster_users.blank? ) )
37
+ end
38
+
36
39
  #
37
40
  # We will try to create a cluster_user record whether
38
41
  # the organization is using force mode (if cluster_id isn't present, it will raise a validation error)
@@ -3,16 +3,16 @@
3
3
 
4
4
  <div class="<%=classes_for_remote_modal_body()%>">
5
5
  <div class="row">
6
- <div class="col-xs-12">
6
+ <div class="col-xs-6">
7
7
  <%= f.input :name, as: :string, label: t('klastera.cluster_name') %>
8
8
  </div>
9
- <div class="col-xs-12">
9
+ <div class="col-xs-6">
10
10
  <%= f.input :nid, as: :string, label: t('klastera.cluster_nid') %>
11
11
  </div>
12
- <div class="col-xs-12">
12
+ <div class="col-xs-6">
13
13
  <%= f.input :color, as: :string, label: t('klastera.cluster_color'), input_html: { class: 'color-picker'} %>
14
14
  </div>
15
- <div class="col-xs-12">
15
+ <div class="col-xs-6">
16
16
  <%= f.input :order, as: :string, label: t('klastera.cluster_order') %>
17
17
  </div>
18
18
  </div>
@@ -2,8 +2,8 @@
2
2
  <%= simple_form_for( @transfer, url: cluster_path(@cluster), method: :delete, remote: true, html: { autocomplete: :off, class: 'destroy-form slim-form-field' } ) do |f| %>
3
3
  <%=render 'layouts/remote_form/header', o: @cluster, title: title, fa: :qrcode %>
4
4
  <div class="<%=classes_for_remote_modal_body()%>">
5
- <h4 class="text-center">Esta acción es irreversible.<br/>¿Está seguro?</h4>
6
- <% if ::Cluster.total_records_assign_to(@cluster) > 0 %>
5
+ <h4 class="blank-modal-title text-center">Esta acción es irreversible<br/>¿Está seguro?</h4>
6
+ <% if @cluster.cluster_entities.size > 0 %>
7
7
  <br />
8
8
  <div class="row">
9
9
  <% if can_transfer_and_destroy %>
@@ -1,4 +1,4 @@
1
- <table class="table table-striped table-hover table-condensed table-bordered datatable">
1
+ <table class="table table-striped table-hover table-condensed table-bordered datatable table">
2
2
  <thead>
3
3
  <tr>
4
4
  <th class="text-center cluster-id"><%=t('klastera.cluster_id')%></th>
@@ -6,7 +6,7 @@
6
6
  <th class="text-center cluster-color"><%=t('klastera.cluster_color')%></th>
7
7
  <th class="text-center cluster-name"><%=t('klastera.cluster_name')%></th>
8
8
  <th class="text-center cluster-nid"><%=t('klastera.cluster_nid')%></th>
9
- <th class="cogs-actions four-icons"><span class="fa fa-cogs"></span></th>
9
+ <th class="cogs-actions two-icons"><span class="fa fa-cogs"></span></th>
10
10
  </tr>
11
11
  </thead>
12
12
  <tbody>
@@ -19,7 +19,7 @@
19
19
  </td>
20
20
  <td class="text-center cluster-name"><%= cluster.name %></td>
21
21
  <td class="text-center cluster-nid"><%= cluster.nid %></td>
22
- <td class="cogs-actions four-icons">
22
+ <td class="cogs-actions two-icons">
23
23
  <%= link_to edit_cluster_path(cluster), class:'btn btn-primary btn-xs', title: t('shared.actions.edit'), "data-toggle": "modal", "data-target": "#remote-modal-block" do %>
24
24
  <span class="fa fa-pencil-square-o"></span>
25
25
  <% end %>
@@ -30,12 +30,4 @@
30
30
  </tr>
31
31
  <% end %>
32
32
  </tbody>
33
- </table>
34
- <style type="text/css">
35
- .cluster-id { width: 70px; }
36
- .cluster-order { width: 70px; }
37
- .cluster-color { width: 70px; }
38
- .odd .colorless { color: #F9F9F9 }
39
- .even .colorless { color: #FFF }
40
- tr:hover .colorless { color: #F5F5F5 }
41
- </style>
33
+ </table>
@@ -18,4 +18,4 @@
18
18
 
19
19
  </div>
20
20
 
21
- <%= render 'layouts/remote_form/modal'%>
21
+ <%= render 'layouts/remote_form/modal', width: 'md' %>
@@ -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, @clusters_session.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,4 @@
1
- <%= simple_form_for(@filter, url: url, remote: true) do |f| %>
1
+ <%= simple_form_for(@cluster_filter, url: url, remote: true) do |f| %>
2
2
 
3
3
  <div class="inline-buttons-block top">
4
4
  <%= button_tag(t('klastera.actions.filter'), class: 'btn btn-primary btn-sm float-right', data: { disable_with: "<i class='fa fa-spinner spin'></i>" }) %>
@@ -7,7 +7,7 @@
7
7
  <%=yield(f) if block_given? %>
8
8
 
9
9
  <% if cluster_organization.is_in_cluster_mode? %>
10
- <% cluster_collection = cluster_clusters.map{|c|[c.name,(c.id||c.nid)]} %>
10
+ <% cluster_collection = cluster_list.map{|c|[c.name,(c.id||c.nid)]} %>
11
11
  <% if cluster_collection.size > 1 %>
12
12
  <div class="inline-label-control-block">
13
13
  <%= f.input :cluster_id, collection: cluster_collection, prompt: t('klastera.clusters.all'), label: false, wrapper: false %>
@@ -3,6 +3,18 @@
3
3
  <% if @user.try(:organization).try(:is_in_cluster_mode?) || other_visibility_reason %>
4
4
  <div class="form-group">
5
5
  <%= f.label t('klastera.cluster_role') %>
6
+ <span
7
+ class="klastera-user-cluster-rol"
8
+ data-title="<%= t('klastera.help.popover.title')%>"
9
+ data-toggle="popover"
10
+ data-content="<%=
11
+ t('klastera.help.popover.content.cluster_role',
12
+ m1: t('klastera.help.roles.description', r: t('klastera.roles.admin'), d: t('klastera.help.roles.admin')),
13
+ m2: t('klastera.help.roles.description', r: t('klastera.roles.user'), d: t("klastera.help.roles.user.#{@user.organization.optional_suborganization_mode? ? :optional : :required}"))
14
+ )%>"
15
+ >
16
+ <%= fa_icon 'info-circle', class: 'btn-link' %>
17
+ </span>
6
18
  <%= f.select :cluster_role, user_cluster_roles.map{|r|[t("klastera.roles.#{r}"),r]}, { include_blank: true }, { class: 'form-control' } %>
7
19
  </div>
8
20
 
@@ -23,5 +35,7 @@
23
35
  });
24
36
  }
25
37
  });
38
+ var popoverTemplate = '<div class="popover" role="tooltip"><div class="arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>'
39
+ $('.klastera-user-cluster-rol').popover({ template: popoverTemplate, html: true, trigger: 'click', });
26
40
  </script>
27
41
  <% end %>
@@ -4,26 +4,18 @@
4
4
  %>
5
5
  <% if cluster_organization.is_in_cluster_mode? || other_visibility_reason %>
6
6
  <%
7
- cluster_collection = @cluster_clusters || cluster_clusters
7
+ cluster_collection = @clusters_session || cluster_list
8
8
  label = t('klastera.cluster.title')
9
9
  %>
10
10
  <% if f.nil? %>
11
11
  <%= label_tag(:cluster_id, label, class: 'control-label') %>
12
12
  <%= select_tag(:cluster_id, options_from_collection_for_select(cluster_collection, 'id', 'display_name_nid'), class: 'form-control', prompt: 'Seleccione') %>
13
13
  <% elsif f.is_a?(SimpleForm::FormBuilder) %>
14
- <% if cluster_collection.size == 1 %>
15
- <%= f.input :lonely_cluster, as: :hidden, html_input: { value: true } %>
16
- <% else %>
17
- <%= f.input :cluster_id, collection: cluster_collection.map{|c|[c.name,c.id]}, label: label %>
18
- <% end %>
14
+ <%= f.input :cluster_id, collection: cluster_collection.map{|c|[c.name,c.id]}, label: label %>
19
15
  <% else %>
20
- <% if cluster_collection.size == 1 %>
21
- <%= f.hidden_field :lonely_cluster, value: true %>
22
- <% else %>
23
- <div class="form-group">
24
- <%= f.label label %>
25
- <%= f.select :cluster_id, cluster_collection.map{|c|[c.name,c.id]}, { include_blank: true }, { class: 'form-control' } %>
26
- </div>
27
- <% end %>
16
+ <div class="form-group">
17
+ <%= f.label label %>
18
+ <%= f.select :cluster_id, cluster_collection.map{|c|[c.name,c.id]}, { include_blank: true }, { class: 'form-control' } %>
19
+ </div>
28
20
  <% end %>
29
21
  <% end %>
@@ -1,5 +1,5 @@
1
1
  <% if cluster_organization.is_in_cluster_mode? %>
2
- <% @cluster_clusters = cluster_clusters %>
2
+ <% @clusters_session = cluster_list(false) %>
3
3
  <div class="col-xs-12">
4
4
  <% if hide_title||=false %>
5
5
  <div class="form-group file required <%=f.object.class.name.parameterize%>_cluster_entity<%=' has-error' if f.object.errors.has_key?(:cluster_entities)%>">
@@ -27,7 +27,7 @@
27
27
  <table id="cluster-entities" class="table table-striped">
28
28
  <tbody class="cluster-entity-rows">
29
29
  <%= f.fields_for :cluster_entities do |cluster_entity|%>
30
- <% next unless @cluster_clusters.map(&:id).include?(cluster_entity.try(:object).try(:cluster_id)) %>
30
+ <% next unless @clusters_session.map(&:id).include?(cluster_entity.try(:object).try(:cluster_id)) %>
31
31
  <%= render 'layouts/klastera/cluster_entity_fields', f: cluster_entity %>
32
32
  <% end %>
33
33
  </body>
@@ -5,10 +5,9 @@
5
5
  data-title="<%= t('klastera.help.popover.title')%>"
6
6
  data-toggle="popover"
7
7
  data-content="<%=
8
- t('klastera.help.popover.content',
8
+ t('klastera.help.popover.content.user_as_cluster_as',
9
9
  m1:t('klastera.help.required_suborganization', t: t('klastera.required_suborganization'), e: t('klastera.clusters.entities')),
10
- m2:t('klastera.help.optional_suborganization', t: t('klastera.optional_suborganization'), e: t('klastera.clusters.entities')),
11
- m3:t('klastera.help.optional_filter', t: t('klastera.optional_filter'), e: t('klastera.clusters.entities'))
10
+ m2:t('klastera.help.optional_suborganization', t: t('klastera.optional_suborganization'), e: t('klastera.clusters.entities'))
12
11
  )%>"
13
12
  >
14
13
  <%= fa_icon 'info-circle', class: 'btn-link' %>
@@ -19,20 +18,4 @@
19
18
  <script type="text/javascript">
20
19
  var popoverTemplate = '<div class="popover" role="tooltip"><div class="arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>'
21
20
  $('.klastera-cluster-option').popover({ template: popoverTemplate, html: true, trigger: 'click', });
22
- </script>
23
-
24
- <style type="text/css">
25
- ul.klastera-option-help {
26
- padding-left: 20px;
27
- list-style-type: disc;
28
- }
29
-
30
- ul.klastera-option-help li {
31
- margin-bottom: 10px;
32
- padding-bottom: 5px;
33
- border-bottom: 1px solid #DDD;
34
- }
35
-
36
- ul.klastera-option-help li b { color: #8A8A8A; font-weight: 400; }
37
- ul.klastera-option-help li b:first-child { color: #2E5F9B; font-weight: bold; }
38
- </style>
21
+ </script>
@@ -9,24 +9,23 @@ es:
9
9
  you_need_add_at_least_one_cluster: Esta organización usa clusters en modo obligatorio. Asigne un cluster al usuario por favor.
10
10
  assign_cluster_role: Asignar role
11
11
  cluster_root_asignation:
12
- title: Asignación Routing Super Admin
13
- text: Este rol es sólo para usuarios Routing
12
+ title: Asignación Super Admin
13
+ text: Este rol es sólo para usuarios super admin
14
14
  roles:
15
- root: Routing Super Admin
16
- admin: Admin Cliente [ Ignora asignación, ve todos los clusters ]
17
- user: Usuario normal [ Ve sólo los clusters asignados ]
15
+ root: Super Admin
16
+ admin: Admin Cluster
17
+ user: Usuario Cluster
18
18
  using_cluster_as: Usando cluster como
19
19
  cluster_order: Orden
20
20
  cluster_id: ID
21
- cluster_role: Cluster rol
21
+ cluster_role: Rol de clusters
22
22
  cluster_name: Nombre
23
23
  cluster_nid: Código
24
24
  cluster_color: Color
25
25
  organization_name: Organización
26
- use_cluster_as: Activar y usar cluster como
27
- required_suborganization: Sub-organización Obligatorio
28
- optional_suborganization: Sub-organización Opcional
29
- optional_filter: Filtro opcional
26
+ use_cluster_as: Activar y usar cluster en modo
27
+ required_suborganization: Obligatorio
28
+ optional_suborganization: Opcional
30
29
  clusters:
31
30
  all: Todos
32
31
  title: Clusters
@@ -71,10 +70,17 @@ es:
71
70
  help:
72
71
  popover:
73
72
  title: Descripción de cada opción
74
- content: "<ul class='klastera-option-help'><li>%{m1}</li><li>%{m2}</li><li>%{m3}</li></ul>"
75
- required_suborganization: "<b>%{t}</b>: Obliga definir un cluster en las entidades %{e} ."
76
- optional_suborganization: "<b>%{t}</b>: Permite definir un cluster en las entidades %{e}."
77
- optional_filter: "<b>%{t}</b>: Permite definir un cluster en las entidades %{e} de forma opcional."
73
+ content:
74
+ user_as_cluster_as: "<ul class='klastera-option-help'><li>%{m1}</li><li>%{m2}</li></ul>"
75
+ required_suborganization: "<b>%{t}</b>: Obliga asignar un cluster a las entidades %{e} ."
76
+ optional_suborganization: "<b>%{t}</b>: Permite asociar un cluster a las entidades %{e}."
77
+ roles:
78
+ description: "<b>%{r}</b>: %{d}."
79
+ root: Ve todos los clusters y no necesita asignación
80
+ admin: Ve todos los clusters y no necesita asignación
81
+ user:
82
+ required: Necesita que se le asigne uno o más clusters, de lo contrario no verá las entidades clusterizadas.
83
+ optional: Si no tiene clusters asignados verá todas la entidades CON y SIN clusters. Si se le asigna un cluster, verá las entidades de ese cluster + las entidades SIN cluster.
78
84
  activemodel:
79
85
  attributes:
80
86
  'klastera/transfer':
@@ -5,140 +5,11 @@ 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
- ]
8
+ UNCLUSTERED_ENTITY = 'without_cluster'.freeze
9
+ KLSTR_HELPERS = %i[ cluster_user cluster_organization cluster_list cluster_scope cluster_scope_through_of user_clusters_string_list ].freeze
13
10
 
14
11
  class << self
15
12
 
16
- def set_cluster_entities_attributes!(entity,array_cluster_ids)
17
- cluster_entities_attributes = {}
18
- entity_cluster_entities = entity.try(:cluster_entities) || []
19
- entity_clusters = entity_cluster_entities.map(&:cluster_id).sort
20
- array_cluster_ids = array_cluster_ids.map(&:id).sort
21
- if array_cluster_ids != entity_clusters
22
- now = DateTime.now
23
- entity_cluster_entities.each_with_index do |ec,index|
24
- remove_cluster = true
25
- if array_cluster_ids.include?(ec.cluster_id)
26
- remove_cluster = false
27
- array_cluster_ids.delete(ec.cluster_id)
28
- end
29
- cluster_entities_attributes[index] = { id: ec.id, cluster_id: ec.cluster_id, _destroy: remove_cluster }
30
- end
31
- array_cluster_ids.each_with_index do |cluster_id,index|
32
- cluster_entities_attributes[now.to_i+index] = { cluster_id: cluster_id, _destroy: false }
33
- end
34
- end
35
- cluster_entities_attributes
36
- end
37
-
38
- #
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.
42
- #
43
- def cluster_scope_filtered!(scope,cluster_id,user,organization)
44
- self.filter_clusterized_collection_with!(
45
- cluster_id,
46
- self.cluster_scope!(scope,user,organization),
47
- organization
48
- )
49
- end
50
-
51
- #
52
- # In order to this works, active_record_collection argument
53
- # should be passed through cluster_scope! method before.
54
- #
55
- def filter_clusterized_collection_with!(cluster_id,active_record_collection,cluster_organization)
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
-
72
- if cluster_id.present?
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.
75
- active_record_collection = active_record_collection.joins(:cluster_entities).where("cluster_entities.cluster_id": cluster_array)
76
- end
77
-
78
- # You should use a block with clusterable data only
79
- yield(active_record_collection) if block_given?
80
- end
81
- active_record_collection
82
- end
83
-
84
- ##
85
- #
86
- #
87
- ##
88
- def set_collection_before_group_by_entity!(active_record_collection,entity_params,cluster_organization)
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
91
- entity_params = entity_params.slice(*entity_params_keys).values
92
- model_class = active_record_collection.model.base_class
93
- model_relations = model_class.reflections.keys
94
- if model_relations.include?(entity_params[0])
95
- entity_params << "#{entity_params[0]}_id".to_sym
96
- if entity_params[0] == 'cluster'
97
- entity_params << :unclustered if cluster_organization.is_in_cluster_mode?
98
- active_record_collection = Klastera.filter_clusterized_collection_with!(
99
- entity_params[2],
100
- active_record_collection,
101
- cluster_organization
102
- )
103
- end
104
- yield( active_record_collection, entity_params_keys.zip(entity_params).to_h )
105
- end
106
- end
107
-
108
- ##
109
- # Returns a ::Cluster::ActiveRecord_Relation from a given scope
110
- #
111
- def clusters_from!(scope,user,organization)
112
- cluster_scope!(scope,user,organization).related_clusters
113
- end
114
-
115
- ##
116
- # Returns a scope filtered by clusters or its
117
- # organization if the cluster mode is not active.
118
- #
119
- def cluster_scope!(scope,user,organization)
120
- scope_klass = scope_class(scope).where(organization_id: organization)
121
- session_clusters(user,organization) do |clusters|
122
- if organization.is_in_cluster_mode?
123
- scope_klass = scope_klass.select("DISTINCT ON (#{scope.table_name}.id) #{scope.table_name}.id, #{scope.table_name}.*")
124
- cluster_ids = clusters.map(&:id)
125
- if organization.required_suborganization_mode?
126
- scope_klass = scope_klass.joins(:cluster_entities).where( cluster_entities: { cluster_id: cluster_ids } )
127
- else
128
- or_these_cluster_ids = cluster_ids.present? ? " OR cluster_entities.cluster_id IN (#{cluster_ids.join(",")})" : ""
129
- scope_klass = scope_klass.joins("
130
- LEFT OUTER JOIN cluster_entities
131
- ON entity_id = #{scope.table_name}.id
132
- AND entity_type = '#{scope}'
133
- ").where("cluster_entities.id IS NULL#{or_these_cluster_ids}")
134
- end
135
- # Provisional fix to avoid SQL clashes due to DISTINCT ON clause
136
- scope_klass = scope_class(scope).eager_load(:cluster_entities).where(id: scope_klass.map(&:id), organization_id: organization)
137
- end
138
- end
139
- scope_klass
140
- end
141
-
142
13
  ##
143
14
  # TODO:
144
15
  # Implement a validation to ensure that
@@ -151,19 +22,22 @@ module Klastera
151
22
  end
152
23
 
153
24
  ##
154
- # Returns a cluster array if organization is using the cluster mode
155
- #
156
- # Use this only to get current_user/organization clusters
157
- # understanding this wont be useful out of a cluster mode context.
25
+ # Returns which clusters a user can see avoiding unnecessary queries if the cluster restraint doesn't apply
158
26
  #
159
- ##
160
- def session_clusters(user,organization)
161
- clusters = organization.is_in_cluster_mode? ? ::ClusterUser.clusters_from(user,organization) : []
162
- if block_given?
163
- clusters = clusters.reject{|c|c.id.blank?}
164
- yield(clusters)
27
+ def cluster_list!(organization,user,include_unclustered=true)
28
+ # Only the cluster mode on and the mandatory user-cluster relation will use a join clause to get the clusters list
29
+ if organization.is_in_cluster_mode? && user.cannot_skip_cluster_clause?
30
+ active_record_collection = ::ClusterUser.clusters_of(organization,user)
31
+ else
32
+ active_record_collection = ::Cluster.where({ organization_id: organization })
165
33
  end
166
- clusters
34
+
35
+ active_record_collection = active_record_collection.order(order: :asc)
36
+
37
+ if include_unclustered && organization.optional_suborganization_mode? # For show and use modes only
38
+ active_record_collection << ::Cluster.new({nid: UNCLUSTERED_ENTITY, name: I18n.t("klastera.#{UNCLUSTERED_ENTITY}")})
39
+ end
40
+ active_record_collection
167
41
  end
168
42
 
169
43
  ##
@@ -181,88 +55,124 @@ module Klastera
181
55
  end
182
56
 
183
57
  ##
184
- # cluster_clusters needs the logged user and its organization
185
- # that why, we perfomed this logic here
58
+ # cluster_list! needs a user and a organization. that why we perfomed this logic here
186
59
  #
187
60
  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))
61
+ @clusters_session ||= Klastera.cluster_list!(organization,user)
62
+ self.entity_clusters_string_list!(cluster_entities, separator, attribute, @clusters_session.map(&:id))
190
63
  end
191
- end
192
64
 
193
- def cluster_user
194
- current_user
195
- end
65
+ #
66
+ # We will try to avoid cluster clause except when:
67
+ # 1.- cluster mode is active
68
+ # AND
69
+ # 2a.- cluster_filter is present (someone wants to filter by cluster)
70
+ # OR
71
+ # 2b.- the current user has some limitations and must checks they cluster relation
72
+ # - User is having clusters in optional_suborganization mode
73
+ # - User IS NOT having clusters in required_suborganization mode
74
+ #
75
+ # For the other hand, with force_cluster_clause we can skip the previous logic if
76
+ # cluster_filter_id is present when the optional_suborganization mode is on. BUT!
77
+ # Be aware that if the cluster_filter is not present, the value of force_cluster_clause
78
+ # will be overridden by the returned value of cannot_skip_cluster_clause? method.
79
+ #
80
+ def cluster_scope!(scope_klass, user, organization, cluster_filter=nil, force_cluster_clause=false)
81
+ scope_klass = scope_class(scope_klass)
82
+ if organization.is_in_cluster_mode? && ( cluster_filter.present? || force_cluster_clause = user.cannot_skip_cluster_clause? ) # yes, this is an assignation
83
+ cluster_ids = []
84
+ # Set another variable as array to get the cluster id(s)
85
+ if cluster_filter.present?
86
+ cluster_ids = cluster_filter.is_a?(Array) ? cluster_filter : [cluster_filter]
87
+ elsif force_cluster_clause
88
+ cluster_ids = ::ClusterUser.clusters_of(organization,user).map(&:id).sort
89
+ end
90
+ # We will avoid the query unless cluster_ids is having values OR force_cluster_clause is set (see method description)
91
+ if cluster_ids.present? || force_cluster_clause
92
+ scope_klass = scope_klass.eager_load(:organization,cluster_entities: :cluster)
93
+ # We add the unclustered if the value of cluster_filter have the special without_cluster string or as method description says
94
+ if cluster_ids.delete(UNCLUSTERED_ENTITY) || ( force_cluster_clause && organization.optional_suborganization_mode? )
95
+ cluster_ids << nil
96
+ end
97
+ scope_klass = scope_klass.where( cluster_entities: { cluster_id: cluster_ids } )
98
+ end
99
+ end
100
+ scope_klass.where(organization_id: organization)
101
+ end
196
102
 
197
- def cluster_organization
198
- current_organization
199
- end
103
+
104
+ # Filter non-clustered entity through a clusterized one
105
+ #
106
+ def cluster_scope_through_of!(relation, cluster_entity_klass, scope_klass, user, organization, cluster_filter=nil, force_cluster_clause=false)
107
+ unclusterized_scope = scope_class(scope_klass)
200
108
 
201
- def user_has_more_than_one_cluster
202
- @cluster_clusters ||= cluster_clusters
203
- @cluster_clusters.size > 1
204
- end
109
+ if organization.is_in_cluster_mode? && ( force_cluster_clause || user.cannot_skip_cluster_clause? )
110
+ unclusterized_scope = unclusterized_scope.joins(relation => :cluster_entities)
111
+ end
112
+
113
+ if scope_klass.respond_to?(:organization)
114
+ unclusterized_scope = unclusterized_scope.where(organization_id: organization)
115
+ end
205
116
 
206
- def set_the_lonely_cluster
207
- form_model = @form_record ? model_name_from_record_or_class(@form_record).param_key : params[:controller].singularize
208
- parameters = params.require( form_model ) rescue nil
209
- lonely_cluster = parameters.blank? ? false : parameters.permit( :lonely_cluster ).present?
210
- if lonely_cluster
211
- params[form_model][:cluster_id] = cluster_clusters.first.try(:id)
117
+ unclusterized_scope.where("#{relation}_id" => cluster_scope!(cluster_entity_klass, user, organization, cluster_filter, force_cluster_clause))
212
118
  end
213
- end
214
119
 
215
- def set_cluster_filter
216
- @filter = ::ClusterFilter.new(cluster_filter_params)
120
+
121
+ # Returns an array with a clusterized scoped result and its grouped version
122
+ #
123
+ def group_by_cluster_scope!(scope_klass, user, organization, cluster_filter=[], scope_scopes=[])
124
+ cluster_ids = cluster_filter.is_a?(Array) ? cluster_filter : [cluster_filter]
125
+ kluster_scope = cluster_scope!(scope_klass, user, organization, cluster_ids, organization.optional_suborganization_mode? )
126
+ scope_scopes.each do |tuple_scope|
127
+ scope_name, scope_arg = tuple_scope
128
+ kluster_scope = scope_arg.present? ? kluster_scope.send(scope_name,scope_arg) : kluster_scope.send(scope_name)
129
+ end
130
+ [
131
+ kluster_scope,
132
+ kluster_scope.order(:cluster_id).group_by do |e|
133
+ e.cluster.present? ? e.cluster.name : I18n.t("klastera.#{UNCLUSTERED_ENTITY}")
134
+ end
135
+ ]
136
+ end
217
137
  end
218
138
 
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)
223
- end
139
+ ##################################################################################################################################################
224
140
 
225
- def cluster_filter_permit_params
226
- [ :cluster_id ].concat( ::ClusterFilter.attributes )
141
+ def cluster_user
142
+ current_user
227
143
  end
228
144
 
229
- def filter_clusterized_collection_with(cluster_id,active_record_collection)
230
- Klastera.filter_clusterized_collection_with!(cluster_id,active_record_collection,cluster_organization)
145
+ def cluster_organization
146
+ current_organization
231
147
  end
232
148
 
233
- def cluster_scope(scope)
234
- Klastera.cluster_scope!(scope,cluster_user,cluster_organization)
149
+ def set_cluster_filter
150
+ cluster_filter_params = params.require(:cluster_filter) rescue {}
151
+ @cluster_filter = ::ClusterFilter.new(
152
+ cluster_filter_params.present? ? cluster_filter_params.permit(
153
+ [ :cluster_id ].concat( ::ClusterFilter.attributes )
154
+ ) : {}
155
+ )
235
156
  end
236
157
 
237
- def cluster_clusters
238
- Klastera.session_clusters(cluster_user,cluster_organization)
158
+ def cluster_list(include_unclustered=true)
159
+ Klastera.cluster_list!(cluster_organization, cluster_user, include_unclustered)
239
160
  end
240
161
 
241
- def cluster_scope_filtered(scope,cluster_id)
242
- Klastera.cluster_scope_filtered!(
243
- scope,
244
- cluster_id,
245
- cluster_user,
246
- cluster_organization
247
- )
162
+ def cluster_scope(scope_klass, cluster_filter=nil, force_cluster_clause=false)
163
+ Klastera.cluster_scope!(scope_klass, cluster_user, cluster_organization, cluster_filter, force_cluster_clause)
248
164
  end
249
165
 
250
- def clusters_from(scope)
251
- Klastera.clusters_from!(scope,cluster_user,cluster_organization)
166
+ def cluster_scope_through_of(relation, cluster_entity_klass, scope_klass, cluster_filter=nil, force_cluster_clause=false)
167
+ Klastera.cluster_scope_through_of!(relation, cluster_entity_klass, scope_klass, cluster_user, cluster_organization, cluster_filter, force_cluster_clause)
252
168
  end
253
169
 
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
- )
170
+ def group_by_cluster_scope(scope_klass, cluster_filter=[], scope_scopes=[])
171
+ Klastera.group_by_cluster_scope!(scope_klass, cluster_user, cluster_organization, cluster_filter, scope_scopes)
262
172
  end
263
173
 
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)
174
+ def user_clusters_string_list(object_entity, separator, attribute=:name)
175
+ Klastera.user_clusters_string_list!(cluster_user, cluster_organization, object_entity.try(:cluster_entities), separator, attribute)
266
176
  end
267
177
 
268
178
  included do
@@ -275,6 +185,5 @@ module Klastera
275
185
  hide_action("#{helper}=")
276
186
  end
277
187
  end
278
- before_action :set_the_lonely_cluster, only: %i[ create update ]
279
188
  end
280
189
  end
@@ -1,3 +1,3 @@
1
1
  module Klastera
2
- VERSION = "1.2.4.2"
2
+ VERSION = "1.4"
3
3
  end
@@ -13,6 +13,11 @@ namespace :klastera do
13
13
  klass = args.entity.constantize
14
14
  ActiveRecord::Base.transaction do
15
15
  klass.where.not(cluster_id: nil).each do |entity|
16
+ if entity.cluster.blank?
17
+ puts "Cluster ID #{entity.cluster_id} was not found!"
18
+ puts "skip..."
19
+ next
20
+ end
16
21
  Klastera::ClusterEntity.create(entity: entity, cluster: entity.cluster)
17
22
  end
18
23
  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.4.2
4
+ version: '1.4'
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-15 00:00:00.000000000 Z
11
+ date: 2020-07-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails