Как добавить контрольное ограничение в миграцию 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