Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions app/models/aliquot/data_for_substitution.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ module Aliquot::DataForSubstitution
def substitution_hash
return if id_previously_changed?

# Take care with saved_changes? - the Aliquot object in memory must be the same one that you called save on,
# otherwise you can't detect the changes.
generate_substitution_hash if saved_changes?
end

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,8 @@ def disable_match_expectation
true
end

# if manifest is reuploaded, only aliquots, that are in 'fake' library tubes will be updated
# Comment is re: a multiplexed library tubes scenario, but this method is used for plates too.
# if manifest is re-uploaded, only aliquots, that are in 'fake' library tubes will be updated
# actual aliquots in multiplexed library tube and other aliquots downstream are updated by this method
# library updates all aliquots in one go, doing it row by row is inefficient and may trigger tag clash
def update_downstream_aliquots
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -295,7 +295,11 @@ def create_specialised_fields

specialised_fields =
columns.with_specialised_fields.map do |column|
column.specialised_field.new(value: at(column.number), sample_manifest_asset: manifest_asset)
column.specialised_field.new(
value: at(column.number),
sample_manifest_asset: manifest_asset,
row: self
)
end

specialised_fields.tap { |fields| link_tag_groups_and_indexes(fields) }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ module Base
end
end

attr_accessor :value, :sample_manifest_asset
attr_accessor :value, :sample_manifest_asset, :row

delegate :present?, to: :value, prefix: true
delegate :asset, :sample, :sample_manifest, to: :sample_manifest_asset
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,30 +26,36 @@ class DualIndexTagWell
def update(_attributes = {})
return unless valid?

# NB. asset here is a well, and a the well_has_single_aliquot? validation ensures there is only one aliquot
stock_aliquot = asset.aliquots.first

# Update all downstream aliquots as well as current aliquot
matching_aliquots = identify_all_matching_aliquots(stock_aliquot)
update_all_relevant_aliquots(matching_aliquots, tag, tag2)
# NB. the asset here is a well, and the well_has_single_aliquot? validation ensures there is only one aliquot
# NB. we are fetching via row so this is the same aliquot instance so saved_changes? works to detect
# substitutions
row.aliquots.first.assign_attributes(tag:, tag2:)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
row.aliquots.first.assign_attributes(tag:, tag2:)
aliquots.first.assign_attributes(tag:, tag2:)

I think we don't need the row passed through. If you look at the code for the other types of library manifest, they reference aliquots directly (which is delegated to asset on the base class) - so should work to do the same here.


Equivalent classes for other manifests:

  • app/sequencescape_excel/sequencescape_excel/specialised_field/i7.rb > app/sample_manifest_excel/sample_manifest_excel/tags/aliquot_updater.rb
  • app/sequencescape_excel/sequencescape_excel/specialised_field/tag_index.rb

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

without the row it does not set up the tag substitutions.
different aliquot instances I think?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

possibly points to some other flaw in how this is working, but I can't see it.

end

def link(other_fields)
self.sf_dual_index_tag_set = other_fields[SequencescapeExcel::SpecialisedField::DualIndexTagSet]
end

# From the validation in DualIndexTagSet, we know this tag set is a valid dual index tag set
# From the validation in DualIndexTagSet, we will know if this tag set is a valid dual index tag set
# with a visible tag group and visible tag2 group
def dual_index_tag_set
@dual_index_tag_set = TagSet.find(sf_dual_index_tag_set.tag_set_id) if sf_dual_index_tag_set&.tag_set_id
end

def tag_group_id
@tag_group_id ||= ::TagGroup.find_by(id: dual_index_tag_set.tag_group_id, visible: true).id
# defensive guard to avoid NoMethodError being thrown when dual_index_tag_set is nil, caught by validation
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Think the comment states the obvious 😃
Great to have fixed the bug at the same time as this story 🙌

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Didn't think it was obvious myself, a validation in a linked specialised field catching it after this code runs.

# in DualIndexTagSet
return unless dual_index_tag_set

@tag_group_id ||= ::TagGroup.find_by(id: dual_index_tag_set.tag_group_id, visible: true)&.id
end

def tag2_group_id
@tag2_group_id ||= ::TagGroup.find_by(id: dual_index_tag_set.tag2_group_id, visible: true).id
# defensive guard to avoid NoMethodError being thrown when dual_index_tag_set is nil, caught by validation
# in DualIndexTagSet
return unless dual_index_tag_set

@tag2_group_id ||= ::TagGroup.find_by(id: dual_index_tag_set.tag2_group_id, visible: true)&.id
end

private
Expand Down Expand Up @@ -82,28 +88,6 @@ def well_has_single_aliquot?
msg = "Expecting well #{asset.map.description} to have a single aliquot, but it has #{asset.aliquots.count}"
errors.add(:base, msg)
end

# Find all aliquots that need updating
# Aliquots must have a matching sample_id, library_id, tag_id and tag2_id to the given stock_aliquot.
def identify_all_matching_aliquots(stock_aliquot)
attributes = {
sample_id: stock_aliquot.sample_id,
library_id: stock_aliquot.library_id,
tag_id: stock_aliquot.tag_id,
tag2_id: stock_aliquot.tag2_id
}

Aliquot.where(attributes).ids
end

# Update the tags in all the matching aliquots
# NB. if active record sees that nothing has changed it will update the record
def update_all_relevant_aliquots(matching_aliquots, i7_tag, i5_tag)
Aliquot.where(id: matching_aliquots).find_each do |aq|
aq.update(tag: i7_tag, tag2: i5_tag)
aq.save!
end
end
end
end
end
15 changes: 6 additions & 9 deletions spec/sequencescape_excel/specialised_field_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -718,8 +718,9 @@ def self.name

describe SequencescapeExcel::SpecialisedField::DualIndexTagWell do
let(:sf_dual_index_tag_well) do
described_class.new(value: dual_index_tag_well, sample_manifest_asset: sample_manifest_asset)
described_class.new(value: dual_index_tag_well, sample_manifest_asset: sample_manifest_asset, row: row)
end
let(:row) { instance_double(SampleManifestExcel::Upload::Row, aliquots: asset.aliquots) }
let(:sf_dual_index_tag_set) do
SequencescapeExcel::SpecialisedField::DualIndexTagSet.new(
value: dual_index_tag_set.name,
Expand All @@ -742,6 +743,7 @@ def self.name

it 'will apply the two tags associated with the map_id' do
sf_dual_index_tag_well.update(aliquot: aliquot, tag_group: nil)
row.aliquots.first.save!
# well location 'A1' => map_id '1'
expect(asset.reload.aliquots.first.tag.map_id).to eq 1
expect(asset.reload.aliquots.first.tag.tag_group).to eq tag_group1
Expand All @@ -763,6 +765,7 @@ def self.name

it 'will apply the 2 tags associated with the updated map_id' do
sf_dual_index_tag_well.update(aliquot: aliquot, tag_group: nil)
row.aliquots.first.save!
# well location 'D1' => map_id '4'
expect(asset.reload.aliquots.first.tag.map_id).to eq 4
expect(asset.reload.aliquots.first.tag2.map_id).to eq 4
Expand Down Expand Up @@ -799,19 +802,13 @@ def self.name
downstream_aliquot2
end

it 'will apply the 2 tags associated with the updated map_id' do
it 'will apply the 2 tags associated with the updated map_id to the source aliquot' do
sf_dual_index_tag_well.update(aliquot: aliquot, tag_group: nil)
row.aliquots.first.save!

# well location 'D1' => map_id '4'
expect(asset.reload.aliquots.first.tag.map_id).to eq 4
expect(asset.reload.aliquots.first.tag2.map_id).to eq 4

# check downstream aliquots updated too
expect(downstream_aliquot1.reload.tag.map_id).to eq 4
expect(downstream_aliquot1.reload.tag2.map_id).to eq 4

expect(downstream_aliquot2.reload.tag.map_id).to eq 4
expect(downstream_aliquot2.reload.tag2.map_id).to eq 4
end
end

Expand Down
Loading