Как добавить ограничение чека в миграцию рельсов?
-
10-10-2019 - |
Вопрос
Мне нужно добавить новую целочисленную колонку в существующую таблицу в моем приложении Rails. В столбце могут быть только значения 1, 2, 3, поэтому я хотел бы добавить ограничение проверки в таблицу/столбца. Как мне указать это ограничение в миграции рельсов?
Решение
Миграция рельсов не обеспечивает никакого способа добавить ограничения, но вы все равно можете сделать это через миграцию, но передавая фактический SQL для выполнения ()
Создать файл миграции:
ruby script/generate Migration AddConstraint
Теперь в файле миграции:
class AddConstraint < ActiveRecord::Migration
def self.up
execute "ALTER TABLE table_name ADD CONSTRAINT check_constraint_name CHECK (check_column_name IN (1, 2, 3) )"
end
def self.down
execute "ALTER TABLE table_name DROP CONSTRAINT check_constraint_name"
end
end
Другие советы
Я только что опубликовал жемчужину для этого: Active_record-postgres-constrints. Анкет Как ПРОЧТИ МЕНЯ Там описывает, что вы можете использовать его с помощью файла db/schema.rb, и он добавляет поддержку следующих методов в миграции:
create_table TABLE_NAME do |t|
# Add columns
t.check_constraint conditions
# conditions can be a String, Array or Hash
end
add_check_constraint TABLE_NAME, conditions
remove_check_constraint TABLE_NAME, CONSTRAINT_NAME
Обратите внимание, что в настоящее время поддерживается только Postgres.
Я только что работал, чтобы получить ограничение на проверку PostgreSQL для работы.
Решение Нилеша не совсем завершено; Файл db/schema.rb не будет включать ограничение, поэтому тесты и любые развертывания, которые используют DB: Setup, не получат ограничения. Согласно http://guides.rubyonrails.org/migrations.html#types-of-schema-dumps
В то время как при миграции вы можете выполнить пользовательские операторы SQL, то, что схема не может восстановить эти операторы из базы данных. Если вы используете подобные функции, то вам следует установить формат схемы на: SQL.
Т.е. в наборе config/application.rb
config.active_record.schema_format = :sql
К сожалению, если вы используете PostgreSQL, вы можете получить ошибку при загрузке результирующего дампа, см. Обсуждение в Ошибка: должен быть владельцем языка plpgsql. Анкет Я не хотел идти по пути конфигурации PostgreSQL в этом обсуждении; Плюс в любом случае мне нравится иметь читаемый файл db/schema.rb. Так что это исключило пользовательский SQL в файле миграции для меня.
А https://github.com/vprokopchuk256/mv-core GEM, предложенный Valera, кажется многообещающим, но он поддерживает лишь ограниченный набор ограничений (и я получил ошибку, когда я попытался его использовать, хотя это может быть связано с несовместимостью с другими драгоценными камнями, которые я включаю).
Решение (взломать), с которым я пошел, состоит в том, чтобы вставить код модели вставить ограничение. Поскольку это все равно, как проверка, вот где я это выразил:
class MyModel < ActiveRecord::Base
validates :my_constraint
def my_constraint
unless MyModel.connection.execute("SELECT * FROM information_schema.check_constraints WHERE constraint_name = 'my_constraint'").any?
MyModel.connection.execute("ALTER TABLE my_models ADD CONSTRAINT my_constraint CHECK ( ...the SQL expression goes here ... )")
end
end
Конечно, это делает дополнительный выбор перед каждой проверкой; Если это проблема, решение будет заключаться в том, чтобы поместить его в патч с обезьяной «после подключения», например, обсуждается в Как запустить конкретный скрипт после подключения к Oracle с помощью Rails? (Вы не можете просто кэшировать результат выбора, потому что добавление проверки/ограничения происходит в рамках транзакции, которая может быть откат назад, поэтому вам нужно проверять каждый раз.)
Вы можете сделать это с GEM Migration Validators. См. Подробности здесь: https://github.com/vprokopchuk256/mv-core
С помощью этого драгоценного камня вы сможете определить проверку включения на уровне БД:
def change
change_table :table_name do |t|
t.integer :column_name, inclusion: [1, 2, 3]
end
end
Более того, вы можете определить, как следует определить эту проверку, и даже сообщение об ошибке, которое должно быть показано:
def change
change_table :posts do |t|
t.integer :priority,
inclusion: { in: [1, 2, 3],
as: :trigger,
message: "can't be anything else than 1, 2, or 3" }
end
end
Вы можете даже повысить уровень этой проверки от миграции на вашу модель:
class Post < ActiveRecord::Base
enforce_migration_validations
end
а затем валидация определяет в миграции также будет определяться как проверка ActiveModel в вашей модели:
Post.new(priority: 3).valid?
=> true
Post.new(priority: 4).valid?
=> false
Post.new(priority: 4).errors.full_messages
=> ["Priority can't be anything else than 1, 2, or 3"]
Вы можете использовать Sequel
жемчужина https://github.com/jeremyevans/eceerel
Sequel.migration do
change do
create_table(:artists) do
primary_key :id
String :name
constraint(:name_min_length){char_length(name) > 2}
end
end
end