Как добавить контрольное ограничение в миграцию Rails?
Мне нужно добавить новый целочисленный столбец в существующую таблицу в моем приложении Rails. Столбец может иметь только значения 1, 2, 3, поэтому я хотел бы добавить контрольное ограничение в таблицу/столбец. Как указать это ограничение в миграции Rails?
5 ответов
Rails migration не предоставляет никакого способа добавить ограничения, но вы все равно можете сделать это через миграцию, но передав фактический 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
Я только что работал над получением ограничения проверки PostgreSQL для работы.
решение Нилеша не совсем завершено; db / schema.файл rb не будет включать ограничение, поэтому тесты и любые развертывания, использующие db:setup, не получат ограничение. По состоянию на http://guides.rubyonrails.org/migrations.html#types-of-schema-dumps
в то время как в миграции вы можете выполнять пользовательские инструкции SQL, dumper схемы не может восстановить их выписки из базы данных. Если вы используете такие функции, вы должны установить схему формат :с SQL.
т. е., в config / application.РБ сет
config.active_record.schema_format = :sql
к сожалению, если вы используете PostgreSQL, вы можете получить ошибку при загрузке результирующего дампа, см. обсуждение в ошибка: должен быть владельцем языка plpgsql. Я не хотел идти по пути конфигурации PostgreSQL в этом обсуждении; плюс в любом случае я люблю иметь читаемый db / schema.файл rb. Таким образом, это исключило пользовательский SQL в файле миграции для меня.
https://github.com/vprokopchuk256/mv-core gem, предложенный Валерой, кажется многообещающим, но он поддерживает только ограниченный набор ограничений (и я получил ошибку, когда попытался использовать его, Хотя это может быть связано с несовместимостью с другими драгоценными камнями, которые я включаю).
решение (Хак) я пошел с это модель код вставить ограничения. Так как это что-то вроде этого как подтверждение, вот где я его поставил:
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? (вы не можете просто кэшировать результат выбора, потому что добавление проверки / ограничения происходит в транзакции, которая может быть откатана, поэтому вам нужно проверить каждый время.)
вы можете сделать это с помощью Migration Validators gem. Подробности смотрите здесь: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
и затем validation defines in migration также будет определена как проверка 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"]
Я только что опубликовал драгоценный камень для этого:active_record-postgres-ограничения. Как README там описано, вы можете использовать его с 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.
можно использовать Sequel
gem https://github.com/jeremyevans/sequel
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