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'].freeze
YES =
'Yes'.freeze
NO =
'No'.freeze
YES_OR_NO =
[YES, NO].freeze
Other_type =
'Other'.freeze
STUDY_SRA_HOLDS =
%w[Hold Public].freeze
DATA_RELEASE_STRATEGY_OPEN =
'open'.freeze
DATA_RELEASE_STRATEGY_MANAGED =
'managed'.freeze
DATA_RELEASE_STRATEGY_NOT_APPLICABLE =
'not applicable'.freeze
DATA_RELEASE_STRATEGIES =
[DATA_RELEASE_STRATEGY_OPEN, DATA_RELEASE_STRATEGY_MANAGED, DATA_RELEASE_STRATEGY_NOT_APPLICABLE].freeze
DATA_RELEASE_TIMING_STANDARD =
'standard'.freeze
DATA_RELEASE_TIMING_NEVER =
'never'.freeze
DATA_RELEASE_TIMING_DELAYED =
'delayed'.freeze
DATA_RELEASE_TIMINGS =
[
  DATA_RELEASE_TIMING_STANDARD,
  'immediate',
  DATA_RELEASE_TIMING_DELAYED
].freeze
DATA_RELEASE_PREVENTION_REASONS =
[
  'data validity',
  'legal',
  'replication of data subset'
].freeze
DATA_RELEASE_DELAY_FOR_OTHER =
'other'.freeze
DATA_RELEASE_DELAY_REASONS_STANDARD =
[
  'phd study',
  DATA_RELEASE_DELAY_FOR_OTHER
].freeze
DATA_RELEASE_DELAY_REASONS_ASSAY =
[
  'phd study',
  'assay of no other use',
  DATA_RELEASE_DELAY_FOR_OTHER
].freeze
DATA_RELEASE_DELAY_PERIODS =
['3 months', '6 months', '9 months', '12 months', '18 months'].freeze

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


99
100
101
# File 'app/models/study.rb', line 99

def approval
  @approval
end

#run_countObject

Returns the value of attribute run_count


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

def run_count
  @run_count
end

#total_priceObject

Returns the value of attribute total_price


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

def total_price
  @total_price
end

Instance Method Details

#abbreviationObject


483
484
485
486
# File 'app/models/study.rb', line 483

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

#accession_all_samplesObject


477
478
479
480
481
# File 'app/models/study.rb', line 477

def accession_all_samples
  if accession_number?
    samples.find_each(&:accession)
  end
end

#accession_number?Boolean

Returns:

  • (Boolean)

473
474
475
# File 'app/models/study.rb', line 473

def accession_number?
  ebi_accession_number.present?
end

#accession_serviceObject


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

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

Returns:

  • (Boolean)

492
493
494
495
# File 'app/models/study.rb', line 492

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))

415
416
417
418
419
# File 'app/models/study.rb', line 415

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

#completedObject


396
397
398
399
400
401
402
403
404
405
406
# File 'app/models/study.rb', line 396

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


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

def dac_accession_number
  .ega_dac_accession_number
end

#dac_refnameObject


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

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

#dehumanise_abbreviated_nameObject


488
489
490
# File 'app/models/study.rb', line 488

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

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


356
357
358
359
360
361
362
363
364
# File 'app/models/study.rb', line 356

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


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

def ebi_accession_number
  .study_ebi_accession_number
end

#ethical_approval_required?Boolean

Returns:

  • (Boolean)

497
498
499
500
501
# File 'app/models/study.rb', line 497

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

#localeObject


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

def locale
  funding_source
end

#mailing_list_of_managersObject


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

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


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

def mark_active
  unless active?
    logger.warn "Study activation failed! #{errors.map(&:to_s)}"
  end
end

#mark_deactiveObject


380
381
382
383
384
# File 'app/models/study.rb', line 380

def mark_deactive
  unless inactive?
    logger.warn "Study deactivation failed! #{errors.map(&: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.


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

def owner
  owners.first
end

#policy_accession_numberObject


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

def policy_accession_number
  .ega_policy_accession_number
end

#rebroadcastObject


535
536
537
# File 'app/models/study.rb', line 535

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)

410
411
412
# File 'app/models/study.rb', line 410

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.


422
423
424
425
426
427
428
# File 'app/models/study.rb', line 422

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

Returns:

  • (Boolean)

511
512
513
# File 'app/models/study.rb', line 511

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

#studyObject

Used by EventfulMailer


444
445
446
# File 'app/models/study.rb', line 444

def study
  self
end

#study_statusObject


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

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

#subject_typeObject


531
532
533
# File 'app/models/study.rb', line 531

def subject_type
  'study'
end

#text_commentsObject


392
393
394
# File 'app/models/study.rb', line 392

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

#unprocessed_submissions?Boolean

Returns:

  • (Boolean)

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

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

#validate_ena_required_fields!Object


515
516
517
518
519
520
# File 'app/models/study.rb', line 515

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


348
349
350
351
352
353
354
# File 'app/models/study.rb', line 348

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


373
374
375
376
377
378
# File 'app/models/study.rb', line 373

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