2011-01-12 136 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的唯一支持。