Подтвердить что ты не робот

Как добавить ограничение проверки в Rails-миграцию?

Мне нужно добавить новый целочисленный столбец в существующую таблицу в моем приложении Rails. В столбце могут быть только значения 1, 2, 3, поэтому я хотел бы добавить контрольное ограничение в таблицу/столбец. Как указать это ограничение в миграции Rails?

4b9b3361

Ответ 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