2011-01-12 135 views

回答

36

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 
+1

另外请注意,如果你添加一个约束,你必须在`config/application.rb`中将`config.active_record.schema_format =:sql`设置为[“`db/schema.rb`不能表达数据库特定项目,如触发器,存储过程或检查约束。“](http://edgeguides.rubyonrails.org/active_record_migrations.html#types-of-schema-dumps)。 – 2017-02-13 01:30:25

+0

现在有一个支持在`db/schema.rb`中存储约束的gem:[active_record-postgres-constraints](https://github.com/on-site/active_record-postgres-constraints)。查看我的答案了解更多详情。目前,只支持postgres。 – 2017-03-17 13:51:14

3

我刚刚通过获取PostgreSQL CHECK约束来工作。

Nilesh的解决方案并不完整; db/schema.rb文件将不包含约束,因此测试和任何使用db:setup的部署都不会获得约束。按照http://guides.rubyonrails.org/migrations.html#types-of-schema-dumps

虽然在迁移,您可以执行自定义SQL语句时, 模式自卸车无法重建从数据库中那些语句。 如果您正在使用这样的功能,那么您应该将架构 格式设置为:sql。

即,在配置/ application.rb中设置

config.active_record.schema_format = :sql 

不幸的是,如果你使用PostgreSQL装载产生的转储时,你可能会得到一个错误,请参阅ERROR: must be owner of language plpgsql讨论。我不想在这个讨论中关注PostgreSQL配置路径;再加上在任何情况下,我喜欢有一个可读的db/schema.rb文件。所以这为我排除了迁移文件中的自定义SQL。

Valera建议的宝石https://github.com/vprokopchuk256/mv-core似乎很有前途,但它只支持一组有限的约束(当我尝试使用它时,我得到了一个错误,虽然这可能是由于与我包括的其他宝石不兼容) 。

我想要的解决方案(hack)是让模型代码插入约束条件。由于它是kindof就像一个验证,这就是我所说的那样:

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 

当然这并各个验证之前一个额外的选择;如果这是一个问题,解决方法是将它放在“连接后”猴子补丁中,如How to run specific script after connected to oracle using rails?(您不能简单地缓存select的结果,因为验证/约束添加发生在可能获得的事务中回滚,所以你需要检查每一次。)

2

你可以使用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 

,然后验证迁移定义也将被定义为加载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"] 
0

您可以使用Sequel宝石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 
2

我刚刚出版了宝石本: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的唯一支持。