Add unique validation and ensure_uniqueness callback while moving folder

[SCI-5312]
This commit is contained in:
Urban Rotnik 2021-01-07 16:45:40 +01:00
parent 88ed583a0c
commit fbce70be0c
2 changed files with 85 additions and 2 deletions

View file

@ -8,10 +8,11 @@ class ProjectFolder < ApplicationRecord
validates :name,
length: { minimum: Constants::NAME_MIN_LENGTH,
maximum: Constants::NAME_MAX_LENGTH },
uniqueness: { scope: :team_id, case_sensitive: false }
uniqueness: { scope: %i(team_id parent_folder_id), case_sensitive: false }
validate :parent_folder_team, if: -> { parent_folder.present? }
before_validation :inherit_team_from_parent_folder, on: :create, if: -> { parent_folder.present? }
before_validation :ensure_uniqueness_name_on_moving, on: :update, if: -> { parent_folder_id_changed? }
belongs_to :team, inverse_of: :project_folders, touch: true
belongs_to :parent_folder, class_name: 'ProjectFolder', optional: true
@ -101,4 +102,20 @@ class ProjectFolder < ApplicationRecord
errors.add(:parent_folder, I18n.t('activerecord.errors.models.project_folder.attributes.parent_folder'))
end
def ensure_uniqueness_name_on_moving
return unless self.class.where(parent_folder: parent_folder).where('name ILIKE ?', name).any?
regex = /\((\d+)\)/
max_number = self.class
.where(parent_folder: parent_folder)
.where('name ILIKE ?', "#{name} (%)")
.order(name: :desc)
.pluck(:name)
.select { |s| s.match(regex) }
.map { |s| s.match(regex)[1].to_i }
.max || 0
self.name = name + " (#{max_number + 1})"
end
end

View file

@ -37,7 +37,7 @@ describe ProjectFolder, type: :model do
.is_at_most(Constants::NAME_MAX_LENGTH))
end
it do
expect(project_folder).to validate_uniqueness_of(:name).scoped_to(:team_id).case_insensitive
expect(project_folder).to validate_uniqueness_of(:name).scoped_to(%i(team_id parent_folder_id)).case_insensitive
end
end
@ -62,5 +62,71 @@ describe ProjectFolder, type: :model do
expect { project_folder.save }.to(change { project_folder.team })
end
end
describe 'ensure_uniqueness_name_on_moving' do
let(:team) { create :team }
let(:parent_folder) { create :project_folder, team: team }
context 'when folder with same name already exists' do
before do
create :project_folder, name: 'FolderOne (some)', parent_folder: parent_folder, team: parent_folder.team
create :project_folder, name: 'FolderOne (test)', parent_folder: parent_folder, team: parent_folder.team
create :project_folder, name: 'FolderOne (111)', parent_folder: parent_folder, team: parent_folder.team
create :project_folder, name: 'FolderOne (41)', parent_folder: parent_folder, team: parent_folder.team
create :project_folder, name: 'FolderOne (1)', parent_folder: parent_folder, team: parent_folder.team
create :project_folder, name: 'FolderOne (0)', parent_folder: parent_folder, team: parent_folder.team
create :project_folder, name: 'FolderOne', parent_folder: parent_folder, team: parent_folder.team
end
it 'appends number to name' do
folder = create :project_folder, team: team, name: 'FolderOne'
folder.update!(parent_folder: parent_folder)
expect(folder.name).to be_eql('FolderOne (112)')
end
it 'keeps number if number is between already existing numbers, but is available' do
folder = create :project_folder, team: team, name: 'FolderOne (40)'
folder.update!(parent_folder: parent_folder)
expect(folder.name).to be_eql('FolderOne (40)')
end
end
context 'when folder with same name does not exsits yet' do
it do
folder = create :project_folder, team: team, name: 'FolderOne'
folder.update!(parent_folder: parent_folder)
expect(folder.name).to be_eql('FolderOne')
end
end
context 'when new name parenthesises with text' do
before do
create :project_folder, name: 'FolderOne (some)', parent_folder: parent_folder, team: parent_folder.team
end
it do
folder = create :project_folder, team: team, name: 'FolderOne (some)'
folder.update!(parent_folder: parent_folder)
expect(folder.name).to be_eql('FolderOne (some) (1)')
end
end
context 'when new name parenthesises with numbers' do
before do
create :project_folder, name: 'FolderOne (1)', parent_folder: parent_folder, team: parent_folder.team
end
it do
folder = create :project_folder, team: team, name: 'FolderOne (1)'
folder.update!(parent_folder: parent_folder)
expect(folder.name).to be_eql('FolderOne (1) (1)')
end
end
end
end
end