Class: Sample
- Inherits:
-
ApplicationRecord
- Object
- ActiveRecord::Base
- ApplicationRecord
- Sample
- Extended by:
- EventfulRecord, Metadata, ValidationStateGuard
- Includes:
- Aliquot::Aliquotable, Api::SampleIo::Extensions, Commentable, ModelExtensions::Sample, Role::Authorized, SharedBehaviour::Named, StandardNamedScopes, Uuid::Uuidable
- Defined in:
- app/models/sample.rb
Overview
A Sample is an abstract concept, with represents the life of a sample of DNA/RNA as it moves through our processes. As a result, a sample may exist in multiple receptacles at the same time, in the form of an Aliquot. As a result Sample is mainly concerned with dealing with aspects which are always true, such as tracking where it originally came from.
An individual sample may be subject to library creation and sequencing multiple different times. These processes may be different each time.
Sample Creation
Samples can enter Sequencescape via a number of different routes. Such as: - SampleManifest: Large spreadsheets of sample information are generated. When uploaded samples are created in the corresponding Receptacle. - Heron: Heron samples get registered via the Api::V2::Heron::PlatesController - Special samples: Samples such as PhiX are generated internally
Defined Under Namespace
Constant Summary collapse
- GC_CONTENTS =
['Neutral', 'High AT', 'High GC'].freeze
- GENDERS =
['Male', 'Female', 'Mixed', 'Hermaphrodite', 'Unknown', 'Not Applicable'].freeze
- DNA_SOURCES =
[ 'Genomic', 'Whole Genome Amplified', 'Blood', 'Cell Line', 'Saliva', 'Brain', 'FFPE', 'Amniocentesis Uncultured', 'Amniocentesis Cultured', 'CVS Uncultured', 'CVS Cultured', 'Fetal Blood', 'Tissue' ].freeze
- SRA_HOLD_VALUES =
%w[Hold Public Protect].freeze
- AGE_REGEXP =
'\d+(?:\.\d+|\-\d+|\.\d+\-\d+\.\d+|\.\d+\-\d+\.\d+)?\s+(?:second|minute|day|week|month|year)s?|Not Applicable|N/A|To be provided'
- DOSE_REGEXP =
rubocop:enable Layout/LineLength
'\d+(?:\.\d+)?\s+\w+(?:\/\w+)?|Not Applicable|N/A|To be provided'
Constants included from Metadata
Constants included from StandardNamedScopes
StandardNamedScopes::SORT_FIELDS, StandardNamedScopes::SORT_ORDERS
Instance Attribute Summary collapse
-
#empty_supplier_sample_name ⇒ Boolean
deprecated
Deprecated.
Only set on older samples where samples were created at manifest generation, rather than upload
Instance Method Summary collapse
- #accession ⇒ Object
- #accession_number? ⇒ Boolean
-
#accession_service ⇒ Object
Return the highest priority accession service.
-
#can_be_included_in_submission? ⇒ Boolean
if sample is registered through sample manifest it should have supplier sample name (without it the row is considered empty) if sample was registered directly, only sample name is a required field, so supplier sample name can be empty but it is reasonably safe to assume that required metadata was provided.
- #control_formatted ⇒ Object
- #ebi_accession_number ⇒ Object
- #ena_study ⇒ Object
- #error ⇒ Object
- #friendly_name ⇒ Object
- #handle_update_event(user) ⇒ Object
- #name_unchanged ⇒ Object
-
#registered_through_manifest? ⇒ Boolean
sample can either be registered through sample manifest, historically through studies/:id/sample_registration or via external services like Heron.
-
#rename_to!(new_name) ⇒ Object
this method has to be before validation_guarded_by.
- #sample_empty?(supplier_sample_name = name) ⇒ Boolean
- #sample_reference_genome ⇒ Object
- #sample_supplier_name_empty?(supplier_sample_name) ⇒ Boolean
-
#shorten_sanger_sample_id ⇒ Object
Truncates the sanger_sample_id for display on labels - Returns the sanger_sample_id AS IS if it is nil or less than 10 characters - Tries to truncate it to the last 7 digits, and returns that - If it cannot extract 7 digits, the full sanger_sample_id is returned Earlier implementations were supposed to fall back to the name in the absence of a sanger_smaple_id, but the feature was incorrectly implemented, and would have thrown an exception.
- #subject_type ⇒ Object
- #validate_ena_required_fields! ⇒ Object
Methods included from EventfulRecord
has_many_events, has_many_lab_events, has_one_event_with_family
Methods included from ValidationStateGuard
validation_guard, validation_guarded_by
Methods included from Metadata
Methods included from Commentable
Methods included from Aliquot::Aliquotable
Methods included from SharedBehaviour::Named
Methods included from StandardNamedScopes
Methods included from Uuid::Uuidable
included, #unsaved_uuid!, #uuid
Methods included from Api::SampleIo::Extensions
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
Instance Attribute Details
#empty_supplier_sample_name ⇒ Boolean
Only set on older samples where samples were created at manifest generation, rather than upload
Returns true if the customer didn't fill in the supplier_sample_name. Indicating that there is actually no sample in the well.
|
# File 'app/models/sample.rb', line 67
|
Instance Method Details
#accession ⇒ Object
508 509 510 511 512 513 514 515 |
# File 'app/models/sample.rb', line 508 def accession return unless configatron.accession_samples accessionable = Accession::Sample.new(Accession.configuration., self) # Accessioning jobs are lower priority (higher number) than submissions and reports Delayed::Job.enqueue(SampleAccessioningJob.new(accessionable), priority: 200) if accessionable.valid? end |
#accession_number? ⇒ Boolean
477 478 479 |
# File 'app/models/sample.rb', line 477 def accession_number? ebi_accession_number.present? end |
#accession_service ⇒ Object
Return the highest priority accession service
497 498 499 500 501 502 503 504 505 506 |
# File 'app/models/sample.rb', line 497 def accession_service services = studies.group_by { |s| s.accession_service.priority } return UnsuitableAccessionService.new([]) if services.empty? highest_priority = services.keys.max suitable_study = services[highest_priority].detect(&:send_samples_to_service?) return suitable_study.accession_service if suitable_study UnsuitableAccessionService.new(services[highest_priority]) end |
#can_be_included_in_submission? ⇒ Boolean
if sample is registered through sample manifest it should have supplier sample name (without it the row is considered empty) if sample was registered directly, only sample name is a required field, so supplier sample name can be empty but it is reasonably safe to assume that required metadata was provided
568 569 570 |
# File 'app/models/sample.rb', line 568 def can_be_included_in_submission? registered_through_manifest? ? .supplier_name.present? : true end |
#control_formatted ⇒ Object
572 573 574 575 576 577 578 579 |
# File 'app/models/sample.rb', line 572 def control_formatted return nil if control.nil? return 'No' if control == false type_text = control_type || 'type unspecified' "Yes (#{type_text})" end |
#ebi_accession_number ⇒ Object
473 474 475 |
# File 'app/models/sample.rb', line 473 def ebi_accession_number .sample_ebi_accession_number end |
#ena_study ⇒ Object
521 522 523 |
# File 'app/models/sample.rb', line 521 def ena_study studies.first end |
#error ⇒ Object
481 482 483 |
# File 'app/models/sample.rb', line 481 def error 'Default error message' end |
#friendly_name ⇒ Object
548 549 550 |
# File 'app/models/sample.rb', line 548 def friendly_name sanger_sample_id || name end |
#handle_update_event(user) ⇒ Object
517 518 519 |
# File 'app/models/sample.rb', line 517 def handle_update_event(user) events.updated_using_sample_manifest!(user) end |
#name_unchanged ⇒ Object
552 553 554 555 |
# File 'app/models/sample.rb', line 552 def name_unchanged errors.add(:name, 'cannot be changed') unless can_rename_sample can_rename_sample end |
#registered_through_manifest? ⇒ Boolean
sample can either be registered through sample manifest, historically through studies/:id/sample_registration or via external services like Heron
560 561 562 |
# File 'app/models/sample.rb', line 560 def registered_through_manifest? sample_manifest.present? end |
#rename_to!(new_name) ⇒ Object
this method has to be before validation_guarded_by
369 370 371 |
# File 'app/models/sample.rb', line 369 def rename_to!(new_name) update!(name: new_name) end |
#sample_empty?(supplier_sample_name = name) ⇒ Boolean
485 486 487 488 489 |
# File 'app/models/sample.rb', line 485 def sample_empty?(supplier_sample_name = name) return true if empty_supplier_sample_name sample_supplier_name_empty?(supplier_sample_name) end |
#sample_reference_genome ⇒ Object
532 533 534 535 536 537 |
# File 'app/models/sample.rb', line 532 def sample_reference_genome return .reference_genome if .reference_genome.try(:name).present? return study_reference_genome if study_reference_genome.try(:name).present? nil end |
#sample_supplier_name_empty?(supplier_sample_name) ⇒ Boolean
491 492 493 494 |
# File 'app/models/sample.rb', line 491 def sample_supplier_name_empty?(supplier_sample_name) supplier_sample_name.blank? || ['empty', 'blank', 'water', 'no supplier name available', 'none'].include?(supplier_sample_name.downcase) end |
#shorten_sanger_sample_id ⇒ Object
This appears to be set up to handle legacy data. All currently generated Sanger sample ids will be meet criteria 1 or 2.
Truncates the sanger_sample_id for display on labels - Returns the sanger_sample_id AS IS if it is nil or less than 10 characters - Tries to truncate it to the last 7 digits, and returns that - If it cannot extract 7 digits, the full sanger_sample_id is returned Earlier implementations were supposed to fall back to the name in the absence of a sanger_smaple_id, but the feature was incorrectly implemented, and would have thrown an exception.
460 461 462 463 464 465 466 467 468 469 470 471 |
# File 'app/models/sample.rb', line 460 def shorten_sanger_sample_id case sanger_sample_id when nil sanger_sample_id when sanger_sample_id.size < 10 sanger_sample_id when /(\d{7})$/ Regexp.last_match(1) else sanger_sample_id end end |
#subject_type ⇒ Object
539 540 541 |
# File 'app/models/sample.rb', line 539 def subject_type 'sample' end |
#validate_ena_required_fields! ⇒ Object
525 526 527 528 529 530 |
# File 'app/models/sample.rb', line 525 def validate_ena_required_fields! (valid?(:accession) && valid?(accession_service.provider)) || raise(ActiveRecord::RecordInvalid, self) rescue ActiveRecord::RecordInvalid => e ena_study.errors..each { || errors.add(:base, "#{} on study") } unless ena_study.nil? raise e end |