如何在Rails迁移中添加检查约束?

Jef*_*eff 30 ruby mysql ruby-on-rails database-migration

我需要在我的Rails应用程序中的现有表中添加一个新的整数列.该列只能有值1,2,3,所以我想在表/列中添加一个检查约束.如何在Rails迁移中指定此约束?

Nil*_*esh 46

Rails迁移不提供任何添加约束的方法,但您仍然可以通过迁移来实现,但是将实际的SQL传递给execute()

创建迁移文件:

ruby script/generate Migration AddConstraint
Run Code Online (Sandbox Code Playgroud)

现在,在迁移文件中:

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
Run Code Online (Sandbox Code Playgroud)

  • 另请注意,如果您确实添加了约束,则必须在 `config/application.rb` 中设置 `config.active_record.schema_format = :sql` 作为 ["`db/schema.rb` 不能表达数据库特定项目,例如作为触发器、存储过程或检查约束。”](http://edgeguides.rubyonrails.org/active_record_migrations.html#types-of-schema-dumps)。 (3认同)

Mar*_*n13 16

Rails 6.1+ 检查约束

Rails 6.1 添加了对数据库迁移检查约束的基本支持

所以现在,用于添加将整数列值限制为 1、2 和 3 的检查约束的迁移可以编写如下:

class AddConstraint < ActiveRecord::Migration
  def up
    add_check_constraint :table_name, 'check_column_name IN (1, 2, 3)', name: 'check_constraint_name'
  end

  def down
    remove_check_constraint :table_name, name: 'check_constraint_name'
  end
end
Run Code Online (Sandbox Code Playgroud)

这是相对 PR 的链接,您可以在其中找到有关add_check_constraint和 的更多详细信息remove_check_constraint

  • 这应该是新接受的答案(或者至少被标记为现代解决方案)。谢谢! (4认同)

小智 5

您可以使用 Migration Validators gem 来完成。在此处查看详细信息:https : //github.com/vprokopchuk256/mv-core

使用该 gem,您将能够在 db 级别定义包含验证:

def change
  change_table :table_name do |t|
    t.integer :column_name, inclusion: [1, 2, 3]
  end
end
Run Code Online (Sandbox Code Playgroud)

此外,您可以定义如何定义验证,甚至应该显示错误消息:

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
Run Code Online (Sandbox Code Playgroud)

您甚至可以升级从迁移到模型的验证:

class Post < ActiveRecord::Base 
  enforce_migration_validations
end
Run Code Online (Sandbox Code Playgroud)

然后迁移中的验证定义也将定义为模型中的 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"]
Run Code Online (Sandbox Code Playgroud)


Isa*_*esh 5

此答案已于 2021 年 5 月过时

我刚刚为此发布了一个 gem:active_record-postgres-constraints。正如那里的自述文件所描述的那样,您可以将它与 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
Run Code Online (Sandbox Code Playgroud)

请注意,此时仅支持 postgres。