diff --git a/app/models/institution_subject.rb b/app/models/institution_subject.rb index 0f23adc8e0..f7c27df4bc 100644 --- a/app/models/institution_subject.rb +++ b/app/models/institution_subject.rb @@ -13,6 +13,7 @@ # # index_institutions_subjects_on_institution_id (institution_id) # index_institutions_subjects_on_subject_id (subject_id) +# unique_institution_subject_in_institution (subject_id,institution_id,description) UNIQUE # # Foreign Keys # @@ -36,6 +37,18 @@ class InstitutionSubject < ApplicationRecord has_many :experts, through: :experts_subjects, inverse_of: :institutions_subjects has_many :not_deleted_experts, through: :experts_subjects, inverse_of: :institutions_subjects + # :institution + # Other InstitutionSubjects of the same Institution, and the same Subject. + has_many :similar_institutions_subjects, -> (is) { where(subject: is.subject).where.not(id: is.id) }, + through: :institution, source: :institutions_subjects, inverse_of: :similar_institutions_subjects + + # Validations + # + # In an Institution, the same subject can only be selected several times` + # if the description is different (and present.) + validates :subject, uniqueness: { scope: [:institution_id, :description] } + validate :validate_description_presence + ## Scopes # scope :support_subjects, -> do @@ -53,6 +66,15 @@ def to_s description end + ## Name / Description uniqueness + # + def validate_description_presence + # description mustn't be blank if there’s a similar subject + if description.blank? && similar_institutions_subjects.present? + errors.add(:description, :blank) + end + end + ## used for serialization in advisors csv # def csv_identifier diff --git a/app/models/subject.rb b/app/models/subject.rb index deafc03667..ea4f5a326c 100644 --- a/app/models/subject.rb +++ b/app/models/subject.rb @@ -15,6 +15,7 @@ # Indexes # # index_subjects_on_archived_at (archived_at) +# index_subjects_on_label (label) UNIQUE # index_subjects_on_slug (slug) UNIQUE # index_subjects_on_theme_id (theme_id) # @@ -38,6 +39,7 @@ class Subject < ApplicationRecord ## Validations # validates :theme, :slug, presence: true + validates :label, presence: true, uniqueness: true before_validation :compute_slug before_save :set_support diff --git a/db/migrate/20201002163301_make_subject_label_unique.rb b/db/migrate/20201002163301_make_subject_label_unique.rb new file mode 100644 index 0000000000..f4ab4c646b --- /dev/null +++ b/db/migrate/20201002163301_make_subject_label_unique.rb @@ -0,0 +1,6 @@ +class MakeSubjectLabelUnique < ActiveRecord::Migration[6.0] + def change + add_index :subjects, :label, unique: true + add_index :institutions_subjects, [:subject_id, :institution_id, :description], unique: true, name: 'unique_institution_subject_in_institution' + end +end diff --git a/db/schema.rb b/db/schema.rb index 6e720703c2..1a6c004681 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 2020_10_02_071333) do +ActiveRecord::Schema.define(version: 2020_10_02_163301) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -243,6 +243,7 @@ t.datetime "created_at", null: false t.datetime "updated_at", null: false t.index ["institution_id"], name: "index_institutions_subjects_on_institution_id" + t.index ["subject_id", "institution_id", "description"], name: "unique_institution_subject_in_institution", unique: true t.index ["subject_id"], name: "index_institutions_subjects_on_subject_id" end @@ -370,6 +371,7 @@ t.boolean "is_support", default: false t.string "slug", null: false t.index ["archived_at"], name: "index_subjects_on_archived_at" + t.index ["label"], name: "index_subjects_on_label", unique: true t.index ["slug"], name: "index_subjects_on_slug", unique: true t.index ["theme_id"], name: "index_subjects_on_theme_id" end diff --git a/doc/domain_model.pdf b/doc/domain_model.pdf index 682ca3a625..98b13b131d 100644 Binary files a/doc/domain_model.pdf and b/doc/domain_model.pdf differ diff --git a/spec/models/institution_subject_spec.rb b/spec/models/institution_subject_spec.rb index 8b99dc78d1..826b1127a5 100644 --- a/spec/models/institution_subject_spec.rb +++ b/spec/models/institution_subject_spec.rb @@ -8,6 +8,45 @@ is_expected.to belong_to :subject is_expected.to belong_to :institution end + + describe 'description uniqueness in an institution' do + let(:institution) { create :institution } + let(:the_subject) { create :subject } + + before do + create :institution_subject, institution: institution, subject: the_subject, description: 'FOO' + end + + context 'same institution and subject and description' do + subject { build :institution_subject, institution: institution, subject: the_subject, description: 'FOO' } + + it { is_expected.not_to be_valid } + end + + context 'same institution and subject, no description' do + subject { build :institution_subject, institution: institution, subject: the_subject, description: '' } + + it { is_expected.not_to be_valid } + end + + context 'same institution and subject, differetn description' do + subject { build :institution_subject, institution: institution, subject: the_subject, description: 'BAR' } + + it { is_expected.to be_valid } + end + + context 'same institution, other subject' do + subject { build :institution_subject, institution: institution } + + it { is_expected.to be_valid } + end + + context 'other institution, same subject' do + subject { build :institution_subject, subject: the_subject } + + it { is_expected.to be_valid } + end + end end describe 'csv_identifier' do