Мне нужно добавить новый целочисленный столбец в существующую таблицу в моем приложении Rails. В столбце могут быть только значения 1, 2, 3, поэтому я хотел бы добавить контрольное ограничение в таблицу/столбец. Как указать это ограничение в миграции Rails?
Как добавить ограничение проверки в Rails-миграцию?
Ответ 1
Перенос Rails не дает возможности добавлять ограничения, но вы все равно можете сделать это с помощью миграции, но путем передачи фактического 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
Ответ 2
Я только что проработал, чтобы заставить ограничение PostgreSQL CHECK работать.
Решение Nilesh не совсем полно; файл db/schema.rb не будет включать ограничение, поэтому тесты и любые развертывания, использующие db: setup, не получат ограничение. По http://guides.rubyonrails.org/migrations.html#types-of-schema-dumps
Во время миграции вы можете выполнять пользовательские инструкции SQL, Хранитель схемы не может восстановить эти утверждения из базы данных. Если вы используете такие функции, то вы должны установить схему формат: sql.
I.e., в config/application.rb set
config.active_record.schema_format = :sql
К сожалению, если вы используете PostgreSQL, вы можете получить сообщение об ошибке при загрузке результирующего дампа, см. обсуждение в ОШИБКА: должен быть владельцем языка plpgsql. Я не хотел идти по пути конфигурации PostgreSQL в этом обсуждении; плюс в любом случае я увлекаюсь чтением читаемого файла db/schema.rb. Таким образом, для меня исключил пользовательский SQL в файле миграции.
https://github.com/vprokopchuk256/mv-core gem, предложенный Валерой, кажется многообещающим, но он поддерживает только ограниченный набор ограничений (и я получил сообщение об ошибке, когда Я пытался использовать его, хотя это может быть связано с несовместимостью с другими драгоценными камнями, которые я включаю).
Решение (hack), с которым я столкнулся, состоит в том, чтобы код модели ввел ограничение. Поскольку это похоже на валидацию, что я сказал:
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
Конечно, это делает дополнительный выбор перед каждой проверкой; если это проблема, решением было бы поместить его в патч обезьяны "после подключения", как описано в Как запустить определенный script после подключения к oracle с помощью рельсов? (Вы не можете просто кэшировать результат выбора, потому что дополнение проверки/ограничения происходит в транзакции, которая может быть откатна, поэтому вам нужно проверять каждый раз.)
Ответ 3
Вы можете сделать это с помощью Gmail. Подробнее здесь: https://github.com/vprokopchuk256/mv-core
С этим камнем вы сможете определить проверку включения на уровне db:
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"]
Ответ 4
Я только что опубликовал камень для этого: active_record-postgres-constraints. Как описано 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.
Ответ 5
Вы можете использовать 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