mirror of
https://github.com/glitch-soc/mastodon.git
synced 2025-12-15 08:48:53 +00:00
fix(tag): prevent dupl. tags on concurrent inserts (#35792)
Co-authored-by: Christian Oelschlegel <oelschle@sciphy.de> Co-authored-by: Claire <claire.github-309c@sitedethib.com>
This commit is contained in:
committed by
GitHub
parent
048746e56b
commit
1f9ddb7cf6
@@ -112,8 +112,14 @@ class Tag < ApplicationRecord
|
|||||||
names = Array(name_or_names).map { |str| [normalize(str), str] }.uniq(&:first)
|
names = Array(name_or_names).map { |str| [normalize(str), str] }.uniq(&:first)
|
||||||
|
|
||||||
names.map do |(normalized_name, display_name)|
|
names.map do |(normalized_name, display_name)|
|
||||||
tag = matching_name(normalized_name).first || create(name: normalized_name,
|
tag = begin
|
||||||
display_name: display_name.gsub(HASHTAG_INVALID_CHARS_RE, ''))
|
matching_name(normalized_name).first || create!(
|
||||||
|
name: normalized_name,
|
||||||
|
display_name: display_name.gsub(HASHTAG_INVALID_CHARS_RE, '')
|
||||||
|
)
|
||||||
|
rescue ActiveRecord::RecordNotUnique
|
||||||
|
find_normalized(normalized_name)
|
||||||
|
end
|
||||||
|
|
||||||
yield tag if block_given?
|
yield tag if block_given?
|
||||||
|
|
||||||
|
|||||||
@@ -265,6 +265,27 @@ RSpec.describe Tag do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe '.find_or_create_by_names_race_condition' do
|
||||||
|
it 'handles simultaneous inserts of the same tag in different cases without error' do
|
||||||
|
tag_name_upper = 'Rails'
|
||||||
|
tag_name_lower = 'rails'
|
||||||
|
|
||||||
|
threads = []
|
||||||
|
|
||||||
|
2.times do |i|
|
||||||
|
threads << Thread.new do
|
||||||
|
described_class.find_or_create_by_names(i.zero? ? tag_name_upper : tag_name_lower)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
threads.each(&:join)
|
||||||
|
|
||||||
|
tags = described_class.where('lower(name) = ?', tag_name_lower.downcase)
|
||||||
|
expect(tags.count).to eq(1)
|
||||||
|
expect(tags.first.name.downcase).to eq(tag_name_lower.downcase)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
describe '.search_for' do
|
describe '.search_for' do
|
||||||
it 'finds tag records with matching names' do
|
it 'finds tag records with matching names' do
|
||||||
tag = Fabricate(:tag, name: 'match')
|
tag = Fabricate(:tag, name: 'match')
|
||||||
|
|||||||
Reference in New Issue
Block a user