Class: Labimotion::Element

Inherits:
ApplicationRecord
  • Object
show all
Includes:
Collectable, ElementUIStateScopes, GenericRevisions, LinkedProperties, Segmentable, Workflow, PgSearch::Model, Taggable
Defined in:
lib/labimotion/models/element.rb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from LinkedProperties

#detach_properties

Methods included from GenericRevisions

#create_vault, #delete_attachments, #save_to_vault

Methods included from Segmentable

#copy_segments, #save_segments, #touch_analyses_properties, #touch_element_properties, #touch_properties_for_object, #touch_segments_properties, #touch_vocabulary

Methods included from Workflow

#split_workflow

Instance Attribute Details

#can_copyObject

Returns the value of attribute can_copy.



24
25
26
# File 'lib/labimotion/models/element.rb', line 24

def can_copy
  @can_copy
end

Class Method Details

.fetch_for_user(user_id, name: nil, short_label: nil, klass_id: nil, limit: 20) ⇒ Object

Fetch elements for a user (owned + shared)



120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
# File 'lib/labimotion/models/element.rb', line 120

def self.fetch_for_user(user_id, name: nil, short_label: nil, klass_id: nil, limit: 20)
  # Prevent abuse by capping and validating limit
  limit = [limit.to_i, 100].min
  limit = 20 if limit <= 0

  # Build base scope with common filters
  apply_filters = lambda do |scope|
    scope = scope.where('elements.name ILIKE ?', "%#{sanitize_sql_like(name)}%") if name.present?
    scope = scope.where('elements.short_label ILIKE ?', "%#{sanitize_sql_like(short_label)}%") if short_label.present?
    scope = scope.by_klass_id(klass_id) if klass_id.present?
    scope
  end

  # Owned elements
  owned = apply_filters.call(
    joins(collections: :user).where(collections: { user_id: user_id })
  )

  # Shared (synced) elements
  shared = apply_filters.call(
    joins(collections: :sync_collections_users).where(sync_collections_users: { user_id: user_id })
  )

  # Combine (remove duplicates), order, and limit
  from("(#{owned.to_sql} UNION #{shared.to_sql}) AS elements")
    .order(short_label: :desc)
    .limit(limit)
end

.get_associated_elements(element_ids) ⇒ Object



104
105
106
107
108
109
110
111
112
113
114
115
116
117
# File 'lib/labimotion/models/element.rb', line 104

def self.get_associated_elements(element_ids)
  pids = Labimotion::Element.where(id: element_ids).pluck :id
  get_ids = proc do |eids|
    eids.each do |p|
      cs = Labimotion::Element.find_by(id: p)&.elements.where.not(id: pids).pluck :id
      next if cs.empty?

      pids = (pids << cs).flatten.uniq
      get_ids.call(cs)
    end
  end
  get_ids.call(pids)
  pids
end

.get_associated_samples(element_ids) ⇒ Object



77
78
79
# File 'lib/labimotion/models/element.rb', line 77

def self.get_associated_samples(element_ids)
  Labimotion::ElementsSample.where(element_id: element_ids).pluck(:sample_id)
end

Instance Method Details

#analysesObject



81
82
83
# File 'lib/labimotion/models/element.rb', line 81

def analyses
  container ? container.analyses : Container.none
end

#attachmentsObject



73
74
75
# File 'lib/labimotion/models/element.rb', line 73

def attachments
  Attachment.where(attachable_id: self.id, attachable_type: self.class.name)
end

#auto_set_short_labelObject



85
86
87
88
89
90
91
92
93
94
95
96
97
98
# File 'lib/labimotion/models/element.rb', line 85

def auto_set_short_label
  return if short_label && !short_label_changed?

  return if parent && (self.short_label = "#{parent.short_label}-#{parent.children.with_deleted.count.to_i.succ}")

  prefix = element_klass.klass_prefix
  if creator.counters[element_klass.name].nil?
    creator.counters[element_klass.name] = '0'
    creator.update_columns(counters: creator.counters)
    creator.reload
  end
  counter = creator.counters[element_klass.name].to_i.succ
  self.short_label = "#{creator.initials}-#{prefix}#{counter}"
end

#migrate_workflowObject



169
170
171
172
173
174
175
176
# File 'lib/labimotion/models/element.rb', line 169

def migrate_workflow
  return if properties.nil? || properties_release.nil?

  return if properties['flow'].nil? && properties_release['flow'].nil?

  update_column(:properties, split_workflow(properties)) if properties['flow']
  update_column(:properties_release, split_workflow(properties_release)) if properties_release['flow']
end

#preview_attachmentObject

align with eln change on preview attachment



64
65
66
67
# File 'lib/labimotion/models/element.rb', line 64

def preview_attachment
  image_atts = attachments.select(&:type_image?)
  image_atts[0] || attachments[0]
end

#split(user, col_ids) ⇒ Object



156
157
158
159
160
161
162
163
164
165
166
167
# File 'lib/labimotion/models/element.rb', line 156

def split(user, col_ids)
  subelement = self.dup
  subelement.name = self.name if self.name.present?
  subelement.parent = self
  subelement.properties = detach_properties(properties)
  subelement.created_by = user.id
  collections = (Collection.where(id: col_ids) | Collection.where(user_id: user, label: 'All', is_locked: true))
  subelement.collections << collections
  subelement.container = Container.create_root_container
  subelement.save!
  subelement
end

#thumb_svgObject



149
150
151
152
153
154
# File 'lib/labimotion/models/element.rb', line 149

def thumb_svg
  image_atts = attachments.select(&:type_image?)
  attachment = image_atts[0] || attachments[0]
  preview = attachment&.read_thumbnail
  (preview && Base64.encode64(preview)) || 'not available'
end

#update_counterObject



100
101
102
# File 'lib/labimotion/models/element.rb', line 100

def update_counter
  creator.increment_counter element_klass.name
end

#user_labelsObject



69
70
71
# File 'lib/labimotion/models/element.rb', line 69

def user_labels
  tag&.taggable_data&.fetch('user_labels', nil)
end