Class: TagSubstitution

Inherits:
Object
  • Object
show all
Includes:
ActiveModel::Model
Defined in:
app/models/tag_substitution.rb

Overview

A TagSubstitution may be used to replace tags in the event of accidental miss-tagging.

Examples:

Populating from an existing asset

mistagged_lane = Lane.find(1234)
TagSubstitution.new(tameplate_asset: mistagged_lane)

Swapping two tags in response to an RT ticket

TagSubstitution.new(
  user: User.find_by(login: 'ab12'),
  ticket: 'RT#12345',
  comment: 'Accidental tag swap',
  substitutions: [
    {
      sample_id: 100, libary_id: 10,
      original_tag_id: 20, substitute_tag_id: 21,
      original_tag2_id: 200, substitute_tag2_id: 201
    },
    {
      sample_id: 101, libary_id: 11,
      original_tag_id: 21, substitute_tag_id: 20,
      original_tag2_id: 201, substitute_tag2_id: 200
    }
  ]
).save #=> true

Defined Under Namespace

Classes: Substitution

Instance Attribute Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#commentString

Any additional comments regarding the substitution [optional]

Returns:

  • (String)

    free-text comment field



42
43
44
# File 'app/models/tag_substitution.rb', line 42

def comment
  @comment
end

#disable_clash_detectionBoolean

Disable tag-clash detection. Useful in cases where the substitutions only affect one of a pair of tags which is ensuring uniqueness, or where the updated aliquots are not part of a pool.

Returns:

  • (Boolean)

    indicates if clash detection is disabled



47
48
49
# File 'app/models/tag_substitution.rb', line 47

def disable_clash_detection
  @disable_clash_detection
end

#disable_match_expectationBoolean

Disable match-detection. Match detection flags a substitution as invalid if it cannot find aliquots matching the suggested substitution. This can be disabled in cases where this may be expected, such as in re-upload of library manifests. (As the aliquots in the library tubes themselves will have been updated by the manifest)

Returns:

  • (Boolean)

    indicates if match detection



54
55
56
# File 'app/models/tag_substitution.rb', line 54

def disable_match_expectation
  @disable_match_expectation
end

#nameObject



126
127
128
# File 'app/models/tag_substitution.rb', line 126

def name
  @name ||= 'Custom'
end

#substitutionsHash

Provide an array of hashes describing your desired substitutions { sample_id: The id of the sample to change, libary_id: The corresponding library id, original_tag_id: The original tag id, [Required if substitute_tag_id supplied] substitute_tag_id: the replacement tag id, [Optional] original_tag2_id: The original tag2 id, [Required if original_tag2_id supplied] substitute_tag2_id: The replacement tag2 id [Optional] }

Returns:

  • (Hash)

    the substitutions to perform



66
67
68
# File 'app/models/tag_substitution.rb', line 66

def substitutions
  @substitutions
end

#ticketString

The ticket number associated with the substitution, eg RT#123454. Gets recorded in the generated comment [optional]

Returns:

  • (String)

    ticket number



38
39
40
# File 'app/models/tag_substitution.rb', line 38

def ticket
  @ticket
end

#userUser

The user performing the substitution, gets recorded on the generated comments [optional]

Returns:

  • (User)

    the user performing the substitution



33
34
35
# File 'app/models/tag_substitution.rb', line 33

def user
  @user
end

Instance Method Details

#no_duplicate_tag_pairsObject



130
131
132
133
134
135
# File 'app/models/tag_substitution.rb', line 130

def no_duplicate_tag_pairs
  tag_pairs.each_with_object(Set.new) do |pair, set|
    errors.add(:base, "Tag pair #{pair.join('-')} features multiple times in the pool.") if set.include?(pair)
    set << pair
  end
end

#saveBoolean

Perform the substitution, add comments to all tubes and lanes and rebroadcast all flowcells

Returns:

  • (Boolean)

    returns true if the operation was successful, false otherwise



96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
# File 'app/models/tag_substitution.rb', line 96

def save # rubocop:todo Metrics/MethodLength
  return false unless valid?

  # First set all tags to null to avoid the issue of tag clashes
  ActiveRecord::Base.transaction do
    updated_substitutions.each(&:nullify_tags)
    updated_substitutions.each(&:substitute_tags)
    apply_comments
    rebroadcast_flowcells
  end
  true
rescue ActiveRecord::RecordNotUnique => e
  # We'll specifically handle tag clashes here so that we can produce more informative messages
  raise e unless e.message.include?('aliquot_tag_tag2_and_tag_depth_are_unique_within_receptacle')

  errors.add(:base, 'A tag clash was detected while performing the substitutions. No changes have been made.')
  false
end

#substitutions_valid?Boolean

Returns:

  • (Boolean)


77
78
79
80
81
82
83
84
# File 'app/models/tag_substitution.rb', line 77

def substitutions_valid?
  @substitutions.reduce(true) do |valid, sub|
    next valid if sub.valid?

    errors.add(:substitution, sub.errors.full_messages)
    valid && false
  end
end

#template_asset=(asset) ⇒ void

This method returns an undefined value.

Provide an asset to build a tag substitution form Will auto populate the fields on substitutions

Parameters:

  • asset (Receptacle)

    The receptacle which you want to base your substitutions on



121
122
123
124
# File 'app/models/tag_substitution.rb', line 121

def template_asset=(asset)
  @substitutions = asset.aliquots.includes(:sample).map { |aliquot| Substitution.new(aliquot:) }
  @name = asset.display_name
end

#updated_substitutionsObject



90
91
92
# File 'app/models/tag_substitution.rb', line 90

def updated_substitutions
  @updated_substitutions ||= @substitutions.select(&:updated?)
end