From fa8e437957ad4362d9dec2f83093d6780e79c3aa Mon Sep 17 00:00:00 2001 From: Alex Kotov Date: Sat, 20 Jul 2019 18:17:37 +0500 Subject: [PATCH] Add constraints to table "federal_subjects" --- app/models/federal_subject.rb | 29 ++++++++++++- config/locales/activerecord/en.yml | 2 + ...758_add_constraints_to_important_tables.rb | 41 +++++++++++++++++++ db/structure.sql | 8 +++- spec/models/federal_subject_spec.rb | 24 +++++++++++ 5 files changed, 100 insertions(+), 4 deletions(-) create mode 100644 db/migrate/20190720124758_add_constraints_to_important_tables.rb diff --git a/app/models/federal_subject.rb b/app/models/federal_subject.rb index 9ac8bd8..07e5670 100644 --- a/app/models/federal_subject.rb +++ b/app/models/federal_subject.rb @@ -25,9 +25,15 @@ class FederalSubject < ApplicationRecord # Validations # ############### - validates :english_name, presence: true, uniqueness: true + validates :english_name, + presence: true, + uniqueness: true, + length: { in: 1..255 } - validates :native_name, presence: true, uniqueness: true + validates :native_name, + presence: true, + uniqueness: true, + length: { in: 1..255 } validates :number, presence: true, @@ -36,6 +42,9 @@ class FederalSubject < ApplicationRecord validates :timezone, presence: true, format: { with: TIMEZONE_RE } + validate :english_name_looks_realistic + validate :native_name_looks_realistic + ########### # Methods # ########### @@ -47,4 +56,20 @@ class FederalSubject < ApplicationRecord english_name end end + +private + + def english_name_looks_realistic + return if english_name.blank? + + errors.add :english_name, :leading_spaces if english_name.start_with? ' ' + errors.add :english_name, :trailing_spaces if english_name.end_with? ' ' + end + + def native_name_looks_realistic + return if native_name.blank? + + errors.add :native_name, :leading_spaces if native_name.start_with? ' ' + errors.add :native_name, :trailing_spaces if native_name.end_with? ' ' + end end diff --git a/config/locales/activerecord/en.yml b/config/locales/activerecord/en.yml index 3dbf9f1..08d891f 100644 --- a/config/locales/activerecord/en.yml +++ b/config/locales/activerecord/en.yml @@ -102,3 +102,5 @@ en: image_size: 'has too big size' image_format: 'has invalid format: %{content_type}' image_ext: 'has invalid extension: ".%{ext}"' + leading_spaces: 'has leading spaces' + trailing_spaces: 'has trailing spaces' diff --git a/db/migrate/20190720124758_add_constraints_to_important_tables.rb b/db/migrate/20190720124758_add_constraints_to_important_tables.rb new file mode 100644 index 0000000..67a03dd --- /dev/null +++ b/db/migrate/20190720124758_add_constraints_to_important_tables.rb @@ -0,0 +1,41 @@ +# frozen_string_literal: true + +class AddConstraintsToImportantTables < ActiveRecord::Migration[6.0] + def change + constraint :federal_subjects, :english_name, <<~SQL + length(english_name) BETWEEN 1 AND 255 + AND + english_name !~ '^[[:space:]]{1,}' + AND + english_name !~ '[[:space:]]{1,}$' + SQL + + constraint :federal_subjects, :native_name, <<~SQL + length(native_name) BETWEEN 1 AND 255 + AND + native_name !~ '^[[:space:]]{1,}' + AND + native_name !~ '[[:space:]]{1,}$' + SQL + + constraint :federal_subjects, :number, 'number > 0' + end + +private + + def constraint(table, name, check) + reversible do |dir| + dir.up do + execute <<~SQL + ALTER TABLE #{table} ADD CONSTRAINT #{name} CHECK (#{check}) + SQL + end + + dir.down do + execute <<~SQL + ALTER TABLE #{table} DROP CONSTRAINT #{name} + SQL + end + end + end +end diff --git a/db/structure.sql b/db/structure.sql index e2f8b8b..66f0908 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -222,7 +222,10 @@ CREATE TABLE public.federal_subjects ( english_name character varying NOT NULL, native_name character varying NOT NULL, number integer NOT NULL, - timezone interval NOT NULL + timezone interval NOT NULL, + CONSTRAINT english_name CHECK ((((length((english_name)::text) >= 1) AND (length((english_name)::text) <= 255)) AND ((english_name)::text !~ '^[[:space:]]{1,}'::text) AND ((english_name)::text !~ '[[:space:]]{1,}$'::text))), + CONSTRAINT native_name CHECK ((((length((native_name)::text) >= 1) AND (length((native_name)::text) <= 255)) AND ((native_name)::text !~ '^[[:space:]]{1,}'::text) AND ((native_name)::text !~ '[[:space:]]{1,}$'::text))), + CONSTRAINT number CHECK ((number > 0)) ); @@ -1124,6 +1127,7 @@ INSERT INTO "schema_migrations" (version) VALUES ('20190718184543'), ('20190719224405'), ('20190720022446'), -('20190720042127'); +('20190720042127'), +('20190720124758'); diff --git a/spec/models/federal_subject_spec.rb b/spec/models/federal_subject_spec.rb index 2e53787..e742138 100644 --- a/spec/models/federal_subject_spec.rb +++ b/spec/models/federal_subject_spec.rb @@ -16,13 +16,37 @@ RSpec.describe FederalSubject do end describe '#english_name' do + def allow_value(*) + super.for :english_name + end + it { is_expected.to validate_presence_of :english_name } it { is_expected.to validate_uniqueness_of :english_name } + + it do + is_expected.to \ + validate_length_of(:english_name).is_at_least(1).is_at_most(255) + end + + it { is_expected.not_to allow_value ' Foo' } + it { is_expected.not_to allow_value 'Foo ' } end describe '#native_name' do + def allow_value(*) + super.for :native_name + end + it { is_expected.to validate_presence_of :native_name } it { is_expected.to validate_uniqueness_of :native_name } + + it do + is_expected.to \ + validate_length_of(:native_name).is_at_least(1).is_at_most(255) + end + + it { is_expected.not_to allow_value ' Foo' } + it { is_expected.not_to allow_value 'Foo ' } end describe '#number' do