rails migration:postgresql for md5 of random string as default
Rails 3 + postgresql
我希望有一个随机字符串的sha用于列的默认值。
所以,在我的迁移中,我有:
t.string :uniqueid, default: md5(random()::text)
然而,我无法让它实际产生任何东西,我使用了反引号,引号等。 从我看过的例子来看,似乎pg函数只能在SELECT
语句中使用。
这是准确的吗? 有关如何实现这一目标的任何想法?
谢谢
Rails会尝试解释这个:
t.string :uniqueid, default: md5(random()::text)
作为Ruby代码和:default => md5(...)
在Ruby中没有任何意义。 如果你引用它,那么Rails会认为它是一个字符串,并将uniqueid
的默认值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
没有提及新的默认值。 如果你想要一个可用的模式,那么你当然必须将Rails推开并使用SQL模式,而不是将它放在你的application.rb
:
config.active_record.schema_format = :sql
请注意,SQL架构转储在3.2之前一直被破坏,并且在各种Rails版本中存在架构加载问题(但您可以随时使用psql < structure.sql
)。 然后删除schema.rb
并改用structure.sql
。 从好的方面来说,SQL模式转储将跟踪真实的外键,检查约束,触发器......
顺便说一句,如果你真的想要SHA那么你会想看看pgcrypto
的digest
函数 。
当然,这些都不会起作用,因为ActiveRecord太愚蠢了,不能单独留下它不理解的东西。 ActiveRecord在分析从数据库获取的表定义时会看到默认值,但它不会理解它,所以它会忽略它。 然后,在INSERT期间,ActiveRecord似乎坚持为所有列提供值,甚至是您没有为其赋值的列。 结果是,即使您在数据库中附加了合理的默认值,您也会在uniqueid
得到NULL。
那么,你怎么解决这个问题呢? 像往常一样使用ActiveRecord,你假装数据库是一个愚蠢的电子表格,并使用可能的before_create
钩子在Ruby中做所有事情。 或者你可以找到一个比ActiveRecord更少数据库恶意的ORM; 我不确定其他ORM如何处理非常量列默认值。
或者,您可以尝试编写BEFORE INSERT触发器,如果NEW.uniqueid IS NULL
,则会将默认值分配给该列。