Class: Labware

Inherits:
Asset show all
Includes:
AssetLink::Associations, Commentable, SharedBehaviour::Named, Uuid::Uuidable
Defined in:
app/models/labware.rb

Overview

Labware represents a physical object which moves around the lab. It has one or more receptacles. rubocop:disable Metrics/ClassLength

Direct Known Subclasses

Fragment, Lane::Labware, Plate, Tube, TubeRack

Defined Under Namespace

Classes: CommentsController

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from SharedBehaviour::Named

included

Methods included from AssetLink::Associations

included

Methods included from Uuid::Uuidable

included, #unsaved_uuid!, #uuid

Methods included from Commentable

#after_comment_addition

Methods inherited from Asset

#asset_type_for_request_types, #barcode_number, #compatible_purposes, #contained_samples, #details, #generate_barcode, #get_qc_result_value_for, #has_stock_asset?, #label, #label=, #original_stock_plates, #prefix, #printable?, #printable_target, #register_stock!, #request_types, #type, #update_from_qc

Methods included from EventfulRecord

#has_many_events, #has_many_lab_events, #has_one_event_with_family

Methods included from Event::PlateEvents

#event_date, #fluidigm_stamp_date, #gel_qc_date, #pico_date, #qc_started_date, #sequenom_stamp_date

Methods inherited from ApplicationRecord

alias_association, convert_labware_to_receptacle_for, find_by_id_or_name, find_by_id_or_name!

Methods included from Squishify

extended

Methods included from Warren::Callback::ExceptExternallyManaged

#broadcast_except_externally_managed, included

Instance Attribute Details

#storage_location_serviceObject (readonly)

Returns the value of attribute storage_location_service.



12
13
14
# File 'app/models/labware.rb', line 12

def storage_location_service
  @storage_location_service
end

Class Method Details

.find_by_barcode(source_barcode) ⇒ Object Also known as: find_from_barcode



343
344
345
# File 'app/models/labware.rb', line 343

def find_by_barcode(source_barcode)
  with_barcode(source_barcode).first
end

.find_from_any_barcode(source_barcode) ⇒ Object



332
333
334
335
336
337
338
339
340
341
# File 'app/models/labware.rb', line 332

def find_from_any_barcode(source_barcode)
  if source_barcode.blank?
    nil
  elsif /\A[0-9]{1,7}\z/.match?(source_barcode)
    # Just a number
    joins(:barcodes).order(:id).find_by('barcodes.barcode LIKE "__?_"', source_barcode)
  else
    find_by_barcode(source_barcode)
  end
end

.labwhere_locations(labware_barcodes) ⇒ Object

Bulk retrieves locations for multiple labwares at once Returns hash { labware barcode => location string, .. } e.g. { 'DN1234' => 'Sanger - Room 1 - Shelf 2' } Hash has blank values where location was not found for a particular barcode Or raises LabWhereClient::LabwhereException if Labwhere response is unexpected



313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
# File 'app/models/labware.rb', line 313

def labwhere_locations(labware_barcodes) # rubocop:todo Metrics/MethodLength
  info_from_labwhere = LabWhereClient::LabwareSearch.find_locations_by_barcodes(labware_barcodes)

  if info_from_labwhere.blank?
    raise LabWhereClient::LabwhereException, 'Labwhere service did not return information'
  end

  barcodes_to_parentage =
    info_from_labwhere.labwares.each_with_object({}) { |info, obj| obj[info.barcode] = info.location.location_info }

  unless labware_barcodes.count == barcodes_to_parentage.count
    labware_barcodes.each do |barcode|
      # add missing barcodes to the hash, with an empty string for location, for ones that Labwhere didn't return
      barcodes_to_parentage[barcode] ||= ''
    end
  end
  barcodes_to_parentage
end

.map_retention_instructions(values) ⇒ Object

Used for location report



166
167
168
169
170
# File 'app/models/labware.rb', line 166

def self.map_retention_instructions(values)
  return if values.blank?

  values.filter_map { |v| Labware.retention_instructions[v] }
end

.search_for_count_of_labware(params) ⇒ Object



184
185
186
187
188
189
190
191
192
# File 'app/models/labware.rb', line 184

def self.search_for_count_of_labware(params)
  with_faculty_sponsor_ids(params[:faculty_sponsor_ids] || nil)
    .with_study_id(params[:study_id] || nil)
    .with_plate_purpose_ids(params[:plate_purpose_ids] || nil)
    .created_between(params[:start_date], params[:end_date])
    .filter_by_barcode(params[:barcodes] || nil)
    .distinct
    .count
end

.search_for_labware(params) ⇒ Object



172
173
174
175
176
177
178
179
180
181
182
# File 'app/models/labware.rb', line 172

def self.search_for_labware(params)
  with_faculty_sponsor_ids(params[:faculty_sponsor_ids] || nil)
    .with_study_id(params[:study_id] || nil)
    .with_plate_purpose_ids(params[:plate_purpose_ids] || nil)
    .created_between(params[:start_date], params[:end_date])
    .filter_by_barcode(params[:barcodes] || nil)
    .with_retention_instructions(
      map_retention_instructions(params[:retention_instructions])
    )
    .distinct
end

Instance Method Details

#ancestor_of_purpose(ancestor_purpose_id) ⇒ Object



235
236
237
238
239
# File 'app/models/labware.rb', line 235

def ancestor_of_purpose(ancestor_purpose_id)
  return self if plate_purpose_id == ancestor_purpose_id

  ancestors.order(id: :desc).find_by(plate_purpose_id: ancestor_purpose_id)
end

#ancestors_of_purpose(ancestor_purpose_id) ⇒ Object



241
242
243
244
245
# File 'app/models/labware.rb', line 241

def ancestors_of_purpose(ancestor_purpose_id)
  return [self] if plate_purpose_id == ancestor_purpose_id

  ancestors.order(id: :desc).where(plate_purpose_id: ancestor_purpose_id)
end

#childObject



353
354
355
# File 'app/models/labware.rb', line 353

def child
  children.last
end

#display_nameObject



274
275
276
# File 'app/models/labware.rb', line 274

def display_name
  name.presence || "#{sti_type} #{id}"
end

#external_identifierObject



231
232
233
# File 'app/models/labware.rb', line 231

def external_identifier
  "#{sti_type}#{id}"
end

#generate_name(new_name) ⇒ Object

Note:

Overridden on subclasses to append the asset id to the name via on_create callbacks

Assigns name



270
271
272
# File 'app/models/labware.rb', line 270

def generate_name(new_name)
  self.name = new_name
end

#labwareObject

Labware reflects the physical piece of plastic corresponding to an asset



283
284
285
# File 'app/models/labware.rb', line 283

def labware
  self
end

#labwhere_locationObject



278
279
280
# File 'app/models/labware.rb', line 278

def labwhere_location
  @labwhere_location ||= lookup_labwhere_location
end

#parentObject



349
350
351
# File 'app/models/labware.rb', line 349

def parent
  parents.first
end

#poly_metadataActiveRecord::Relation

Returns a collection of PolyMetadatum records.

Returns:

  • (ActiveRecord::Relation)

    a collection of PolyMetadatum records



161
162
163
# File 'app/models/labware.rb', line 161

def 
  PolyMetadatum.where(metadatable_id: id, metadatable_type: self.class.name)
end

#received_dateObject



295
296
297
298
299
300
301
# File 'app/models/labware.rb', line 295

def received_date
  asset_audits # rubocop:disable Style/SafeNavigationChainLength
    &.where('`key` = ? AND message LIKE ?', 'slf_receive_plates', '%Reception fridge%')
    &.order(:created_at)
    &.last
    &.created_at
end

#retention_instructionsObject



303
304
305
# File 'app/models/labware.rb', line 303

def retention_instructions
  @retention_instructions ||= obtain_retention_instructions
end

#roleObject



255
256
257
# File 'app/models/labware.rb', line 255

def role
  (requests_as_source.first || in_progress_requests.first)&.role
end

#scanned_in_dateObject



291
292
293
# File 'app/models/labware.rb', line 291

def scanned_in_date
  scanned_into_lab_event.try(:content) || ''
end

#source_plateObject



259
260
261
# File 'app/models/labware.rb', line 259

def source_plate
  @source_plate ||= purpose&.source_plate(self)
end

#source_platesObject



263
264
265
# File 'app/models/labware.rb', line 263

def source_plates
  @source_plates ||= purpose&.source_plates(self)
end

#spiked_in_bufferObject

Gets the relevant SpikedBuffer tube, if one exists, by using the two associations. A direct parent SpikedBuffer tube is used if it exists, otherwise the most recent ancestor. This was necessary to avoid affecting historical data, for which the direct parent should be used, even though there is another ancestor that was created more recently.



251
252
253
# File 'app/models/labware.rb', line 251

def spiked_in_buffer
  direct_spiked_in_buffer || most_recent_spiked_in_buffer
end

#stateObject

Provided for API compatibility



227
228
229
# File 'app/models/labware.rb', line 227

def state
  nil
end

#storage_locationObject



287
288
289
# File 'app/models/labware.rb', line 287

def storage_location
  @storage_location ||= obtain_storage_location
end