Class: Study

Inherits:
ApplicationRecord show all
Extended by:
EventfulRecord, Metadata
Includes:
AASM, Api::StudyIO::Extensions, Commentable, DataRelease, EventfulRecord, ModelExtensions::Study, ReferenceGenome::Associations, Role::Authorized, SampleManifest::Associations, SharedBehaviour::Named, StudyReport::StudyDetails, Uuid::Uuidable
Defined in:
app/models/study.rb,
app/models/study/metadata.rb

Overview

Study itself will also ensure that this file gets loaded, to make sure the metadata class contains these methods

Defined Under Namespace

Classes: Metadata

Constant Summary collapse

STOCK_PLATE_PURPOSES =

Constants

['Stock Plate', 'Stock RNA Plate']
YES =
'Yes'
NO =
'No'
YES_OR_NO =
[YES, NO]
Other_type =
'Other'
STUDY_SRA_HOLDS =
%w[Hold Public]
DATA_RELEASE_STRATEGY_OPEN =
'open'
DATA_RELEASE_STRATEGY_MANAGED =
'managed'
DATA_RELEASE_STRATEGY_NOT_APPLICABLE =
'not applicable'
DATA_RELEASE_STRATEGIES =
[DATA_RELEASE_STRATEGY_OPEN, DATA_RELEASE_STRATEGY_MANAGED, DATA_RELEASE_STRATEGY_NOT_APPLICABLE]
DATA_RELEASE_TIMING_STANDARD =
'standard'
DATA_RELEASE_TIMING_NEVER =
'never'
DATA_RELEASE_TIMING_DELAYED =
'delayed'
DATA_RELEASE_TIMINGS =
[
  DATA_RELEASE_TIMING_STANDARD,
  'immediate',
  DATA_RELEASE_TIMING_DELAYED
]
DATA_RELEASE_PREVENTION_REASONS =
[
  'data validity',
  'legal',
  'replication of data subset'
]
DATA_RELEASE_DELAY_FOR_OTHER =
'other'
DATA_RELEASE_DELAY_REASONS_STANDARD =
[
  'phd study',
  DATA_RELEASE_DELAY_FOR_OTHER
]
DATA_RELEASE_DELAY_REASONS_ASSAY =
[
  'phd study',
  'assay of no other use',
  DATA_RELEASE_DELAY_FOR_OTHER
]
DATA_RELEASE_DELAY_LONG =
['6 months', '9 months', '12 months', '18 months']
DATA_RELEASE_DELAY_SHORT =
['3 months']
DATA_RELEASE_DELAY_PERIODS =
DATA_RELEASE_DELAY_SHORT + DATA_RELEASE_DELAY_LONG

Constants included from Metadata

Metadata::SECTION_FIELDS

Constants included from StudyReport::StudyDetails

StudyReport::StudyDetails::BATCH_SIZE

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from Metadata

has_metadata, required_tags

Methods included from EventfulRecord

has_many_events, has_many_lab_events, has_one_event_with_family

Methods included from Role::Authorized

included

Methods included from SampleManifest::Associations

included

Methods included from ReferenceGenome::Associations

included

Methods included from SharedBehaviour::Named

included

Methods included from Commentable

#after_comment_addition

Methods included from DataRelease

#ena_accession_required?, #for_array_express?, #valid_data_release_properties?

Methods included from Uuid::Uuidable

included, #unsaved_uuid!, #uuid

Methods included from Api::StudyIO::Extensions

included, #render_class

Methods included from StudyReport::StudyDetails

#each_stock_well_id_in_study_in_batches, #progress_report_header, #progress_report_on_all_assets

Methods inherited from ApplicationRecord

convert_labware_to_receptacle_for, find_by_id_or_name, find_by_id_or_name!

Methods included from Warren::BroadcastMessages

#broadcast, included, #queue_associated_for_broadcast, #queue_for_broadcast, #warren

Instance Attribute Details

#approvalObject

Returns the value of attribute approval


101
102
103
# File 'app/models/study.rb', line 101

def approval
  @approval
end

#run_countObject

Returns the value of attribute run_count


102
103
104
# File 'app/models/study.rb', line 102

def run_count
  @run_count
end

#total_priceObject

Returns the value of attribute total_price


103
104
105
# File 'app/models/study.rb', line 103

def total_price
  @total_price
end

Instance Method Details

#abbreviationObject


481
482
483
484
# File 'app/models/study.rb', line 481

def abbreviation
  abbreviation = .study_name_abbreviation
  abbreviation.presence || "#{id}STDY"
end

#accession_all_samplesObject


473
474
475
476
477
478
479
# File 'app/models/study.rb', line 473

def accession_all_samples
  if accession_number?
    samples.find_each do |sample|
      sample.accession
    end
  end
end

#accession_number?Boolean


469
470
471
# File 'app/models/study.rb', line 469

def accession_number?
  ebi_accession_number.present?
end

#accession_serviceObject


501
502
503
504
505
506
507
# File 'app/models/study.rb', line 501

def accession_service
  case data_release_strategy
  when 'open' then EnaAccessionService.new
  when 'managed' then EgaAccessionService.new
  else NoAccessionService.new(self)
  end
end

#approved?Boolean


490
491
492
493
# File 'app/models/study.rb', line 490

def approved?
  # TODO: remove
  true
end

#asset_progress(assets = nil) {|initial_requests.asset_statistics(wheres)| ... } ⇒ Object

Yields information on the state of all assets in a convenient fashion for displaying in a table.

Yields:

  • (initial_requests.asset_statistics(wheres))

411
412
413
414
415
# File 'app/models/study.rb', line 411

def asset_progress(assets = nil)
  wheres = {}
  wheres = { asset_id: assets.map(&:id) } unless assets.blank?
  yield(initial_requests.asset_statistics(wheres))
end

#completedObject


392
393
394
395
396
397
398
399
400
401
402
# File 'app/models/study.rb', line 392

def completed
  counts = requests.standard.group('state').count
  total = counts.values.sum
  failed = counts['failed'] || 0
  cancelled = counts['cancelled'] || 0
  if (total - failed - cancelled) > 0
    (counts.fetch('passed', 0) * 100) / (total - failed - cancelled)
  else
    return 0
  end
end

#dac_accession_numberObject


461
462
463
# File 'app/models/study.rb', line 461

def dac_accession_number
  .ega_dac_accession_number
end

#dac_refnameObject


430
431
432
# File 'app/models/study.rb', line 430

def dac_refname
  "DAC for study - #{name} - ##{id}"
end

#dehumanise_abbreviated_nameObject


486
487
488
# File 'app/models/study.rb', line 486

def dehumanise_abbreviated_name
  abbreviation.downcase.gsub(/ +/, '_')
end

#each_well_for_qc_report_in_batches(exclude_existing, product_criteria, plate_purposes = nil) ⇒ Object


352
353
354
355
356
357
358
359
360
# File 'app/models/study.rb', line 352

def each_well_for_qc_report_in_batches(exclude_existing, product_criteria, plate_purposes = nil)
  base_scope = Well.on_plate_purpose(PlatePurpose.where(name: plate_purposes || STOCK_PLATE_PURPOSES))
                   .for_study_through_aliquot(self)
                   .without_blank_samples
                   .includes(:well_attribute, samples: :sample_metadata)
                   .readonly(true)
  scope = exclude_existing ? base_scope.without_report(product_criteria) : base_scope
  scope.find_in_batches { |wells| yield wells }
end

#ebi_accession_numberObject


457
458
459
# File 'app/models/study.rb', line 457

def ebi_accession_number
  .study_ebi_accession_number
end

#ethical_approval_required?Boolean


495
496
497
498
499
# File 'app/models/study.rb', line 495

def ethical_approval_required?
  (.contains_human_dna == Study::YES &&
  .contaminated_human_dna == Study::NO &&
  .commercially_available == Study::NO)
end

#localeObject


453
454
455
# File 'app/models/study.rb', line 453

def locale
  funding_source
end

#mailing_list_of_managersObject


520
521
522
523
524
525
526
527
# File 'app/models/study.rb', line 520

def mailing_list_of_managers
  configured_managers = managers.pluck(:email).compact.uniq
  if configured_managers.empty?
    configatron.fetch(:ssr_emails, User.all_administrators_emails)
  else
    configured_managers
  end
end

#mark_activeObject


382
383
384
385
386
# File 'app/models/study.rb', line 382

def mark_active
  unless active?
    logger.warn "Study activation failed! #{errors.map { |e| e.to_s }}"
  end
end

#mark_deactiveObject


376
377
378
379
380
# File 'app/models/study.rb', line 376

def mark_deactive
  unless inactive?
    logger.warn "Study deactivation failed! #{errors.map { |e| e.to_s }}"
  end
end

#ownerObject

Returns the study owner (user) if exists or nil TODO - Should be “owners” and return all owners or empty array - done TODO - Look into this is the person that created it really the owner? If so, then an owner should be created when a study is created.


449
450
451
# File 'app/models/study.rb', line 449

def owner
  owners.first
end

#policy_accession_numberObject


465
466
467
# File 'app/models/study.rb', line 465

def policy_accession_number
  .ega_policy_accession_number
end

#rebroadcastObject


533
534
535
# File 'app/models/study.rb', line 533

def rebroadcast
  broadcast
end

#request_progress {|@stats_cache ||= initial_requests.progress_statistics| ... } ⇒ Object

Yields information on the state of all request types in a convenient fashion for displaying in a table. Used initial requests, which won't capture cross study sequencing requests.

Yields:

  • (@stats_cache ||= initial_requests.progress_statistics)

406
407
408
# File 'app/models/study.rb', line 406

def request_progress
  yield(@stats_cache ||= initial_requests.progress_statistics) if block_given?
end

#sample_progress(samples = nil) ⇒ Object

Yields information on the state of all samples in a convenient fashion for displaying in a table.


418
419
420
421
422
423
424
# File 'app/models/study.rb', line 418

def sample_progress(samples = nil)
  if samples.blank?
    requests.sample_statistics_new
  else
    yield(requests.where(aliquots: { sample_id: samples.pluck(:id) }).sample_statistics_new)
  end
end

#send_samples_to_service?Boolean


509
510
511
# File 'app/models/study.rb', line 509

def send_samples_to_service?
  accession_service.no_study_accession_needed || ((!.never_release?) && accession_number?)
end

#studyObject

Used by EventfulMailer


440
441
442
# File 'app/models/study.rb', line 440

def study
  self
end

#study_statusObject


426
427
428
# File 'app/models/study.rb', line 426

def study_status
  inactive? ? 'closed' : 'open'
end

#subject_typeObject


529
530
531
# File 'app/models/study.rb', line 529

def subject_type
  'study'
end

#text_commentsObject


388
389
390
# File 'app/models/study.rb', line 388

def text_comments
  comments.each_with_object([]) { |c, array| array << c.description unless c.description.blank? }.join(', ')
end

#unprocessed_submissions?Boolean


434
435
436
437
# File 'app/models/study.rb', line 434

def unprocessed_submissions?
  # TODO[mb14] optimize if needed
  study.orders.any? { |o| o.submission.nil? || o.submission.unprocessed? }
end

#validate_ena_required_fields!Object


513
514
515
516
517
518
# File 'app/models/study.rb', line 513

def validate_ena_required_fields!
  self.validating_ena_required_fields = true
  valid? or raise ActiveRecord::RecordInvalid, self
ensure
  self.validating_ena_required_fields = false
end

#validate_ethically_approvedObject

Instance methods


344
345
346
347
348
349
350
# File 'app/models/study.rb', line 344

def validate_ethically_approved
  return true if valid_ethically_approved?

  message = ethical_approval_required? ? 'should be either true or false for this study.' : 'should be not applicable (null) not false.'
  errors.add(:ethically_approved, message)
  false
end

#warningsObject


369
370
371
372
373
374
# File 'app/models/study.rb', line 369

def warnings
  # These studies are now invalid, but the warning should remain until existing studies are fixed.
  if .managed? && .data_access_group.blank?
    'No user group specified for a managed study. Please specify a valid Unix user group to ensure study data is visible to the correct people.'
  end
end