3

Rails 3 + postgresqlrails migration:postgresql for md5的隨機字符串作爲默認值

我想要一個隨機字符串作爲列的默認值。

所以,在我的移民,我有:

t.string :uniqueid, default: md5(random()::text)

但是我不能讓這個實際生產任何東西,我用反引號,報價等。從我看到的例子看來,pg函數只能在SELECT聲明中使用。

這是否準確?關於如何實現這一點的任何想法?

感謝

+0

您需要查看生成的SQL,因爲md5(...)調用作爲CREATE/ALTER TABLE中的DEFAULT子句非常有效。 – 2013-03-01 09:39:47

回答

5

Rails會試圖解釋這一點:

t.string :uniqueid, default: md5(random()::text) 

爲Ruby代碼和:default => md5(...)並不意味着紅寶石什麼。如果你引用它,那麼Rails會認爲它是一個字符串,並且爲uniqueid設置字符串'md5(random()::text)'的默認值,這不會起作用。

你的問題是Rails不理解像使用函數作爲列默認值這樣複雜的東西,Rails有一個奇怪的和誤導的概念,你應該在Rails中而不是在數據庫中做所有事情。如果你想在一列中默認使用的函數調用,您可以自己動手完成的alter table

connection.execute(%q{ 
    alter table your_table alter column uniqueid set default md5(random()::text) 
}) 

,將讓你在數據庫中所需的默認,但你可能會注意到,有一個新的不提默認在您的schema.rb。如果你想有一個可用的模式,那麼你就必須這樣做,當然,推導軌的方式進行,並使用SQL schema instead by putting this in your application.rb

config.active_record.schema_format = :sql 

注意SQL模式轉儲被打破,直到3.2,並有在架構加載問題各種Rails版本(但你可以隨時使用psql < structure.sql)。然後刪除schema.rb並使用structure.sql代替。有趣的是,SQL模式轉儲會跟蹤真正的外鍵,檢查約束,觸發器......

順便說一句,如果你真的想要SHA,那麼你會想看看digest function from pgcrypto


當然,這些都不會起作用,因爲ActiveRecord太愚蠢了,不願意讓事情獨自一人,它不理解。 ActiveRecord在分析它從數據庫獲得的表定義時會看到默認值,但它不會理解它,因此它會忽略它。然後,在INSERT過程中,ActiveRecord似乎堅持要爲所有列提供值,即使是沒有分配值的列也是如此。結果是,即使您已在數據庫中附加了合理的默認值,您也會在uniqueid中以NULL結尾。

那麼,你如何解決這個問題?像往常一樣使用ActiveRecord,你假裝數據庫是一個愚蠢的電子表格,並且在Ruby中使用一切,可能是before_create掛鉤。或者你可以找到比ActiveRecord更少的數據庫敵對ORM;我不確定其他ORM將如何處理非常量列默認值。

或者,您可以嘗試編寫一個BEFORE INSERT觸發器,如果​​NEW.uniqueid IS NULL將分配默認值到該列。

+0

connection.execute(...)是你在PG控制檯上做的事情嗎? – cbrulak 2013-03-01 19:48:30

+0

@cbrulak:不,您可以在遷移的「def up」或「def down」方法中執行此操作。你只需要繞過所有的Rails的東西,直接向數據庫交談,這就是'connection.execute'的作用。 – 2013-03-01 19:51:17

+0

好的,那有效。但是,當創建新行時,默認值仍然爲空。任何關於這個問題的觀點? – cbrulak 2013-03-03 06:21:24