mirror of
https://github.com/scinote-eln/scinote-web.git
synced 2024-12-31 04:32:06 +08:00
Add unique validation and ensure_uniqueness callback while moving folder
[SCI-5312]
This commit is contained in:
parent
88ed583a0c
commit
fbce70be0c
2 changed files with 85 additions and 2 deletions
|
@ -8,10 +8,11 @@ class ProjectFolder < ApplicationRecord
|
||||||
validates :name,
|
validates :name,
|
||||||
length: { minimum: Constants::NAME_MIN_LENGTH,
|
length: { minimum: Constants::NAME_MIN_LENGTH,
|
||||||
maximum: Constants::NAME_MAX_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? }
|
validate :parent_folder_team, if: -> { parent_folder.present? }
|
||||||
|
|
||||||
before_validation :inherit_team_from_parent_folder, on: :create, 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 :team, inverse_of: :project_folders, touch: true
|
||||||
belongs_to :parent_folder, class_name: 'ProjectFolder', optional: 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'))
|
errors.add(:parent_folder, I18n.t('activerecord.errors.models.project_folder.attributes.parent_folder'))
|
||||||
end
|
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
|
end
|
||||||
|
|
|
@ -37,7 +37,7 @@ describe ProjectFolder, type: :model do
|
||||||
.is_at_most(Constants::NAME_MAX_LENGTH))
|
.is_at_most(Constants::NAME_MAX_LENGTH))
|
||||||
end
|
end
|
||||||
it do
|
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
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -62,5 +62,71 @@ describe ProjectFolder, type: :model do
|
||||||
expect { project_folder.save }.to(change { project_folder.team })
|
expect { project_folder.save }.to(change { project_folder.team })
|
||||||
end
|
end
|
||||||
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
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue