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
506 507 508 509 510 511 512 513 |
# File 'app/models/sample.rb', line 506 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
475 476 477 |
# File 'app/models/sample.rb', line 475 def accession_number? ebi_accession_number.present? end |
#accession_service ⇒ Object
Return the highest priority accession service
495 496 497 498 499 500 501 502 503 504 |
# File 'app/models/sample.rb', line 495 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
566 567 568 |
# File 'app/models/sample.rb', line 566 def can_be_included_in_submission? registered_through_manifest? ? .supplier_name.present? : true end |
#control_formatted ⇒ Object
570 571 572 573 574 575 576 577 |
# File 'app/models/sample.rb', line 570 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
471 472 473 |
# File 'app/models/sample.rb', line 471 def ebi_accession_number .sample_ebi_accession_number end |
#ena_study ⇒ Object
519 520 521 |
# File 'app/models/sample.rb', line 519 def ena_study studies.first end |
#error ⇒ Object
479 480 481 |
# File 'app/models/sample.rb', line 479 def error 'Default error message' end |
#friendly_name ⇒ Object
546 547 548 |
# File 'app/models/sample.rb', line 546 def friendly_name sanger_sample_id || name end |
#handle_update_event(user) ⇒ Object
515 516 517 |
# File 'app/models/sample.rb', line 515 def handle_update_event(user) events.updated_using_sample_manifest!(user) end |
#name_unchanged ⇒ Object
550 551 552 553 |
# File 'app/models/sample.rb', line 550 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
558 559 560 |
# File 'app/models/sample.rb', line 558 def registered_through_manifest? sample_manifest.present? end |
#rename_to!(new_name) ⇒ Object
this method has to be before validation_guarded_by
367 368 369 |
# File 'app/models/sample.rb', line 367 def rename_to!(new_name) update!(name: new_name) end |
#sample_empty?(supplier_sample_name = name) ⇒ Boolean
483 484 485 486 487 |
# File 'app/models/sample.rb', line 483 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
530 531 532 533 534 535 |
# File 'app/models/sample.rb', line 530 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
489 490 491 492 |
# File 'app/models/sample.rb', line 489 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.
458 459 460 461 462 463 464 465 466 467 468 469 |
# File 'app/models/sample.rb', line 458 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
537 538 539 |
# File 'app/models/sample.rb', line 537 def subject_type 'sample' end |
#validate_ena_required_fields! ⇒ Object
523 524 525 526 527 528 |
# File 'app/models/sample.rb', line 523 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 |