rails migration:postgresql for md5 of random string as default

时间:2013-03-01 07:51:27

标签: ruby-on-rails ruby-on-rails-3 postgresql rails-activerecord rails-migrations

Rails 3 + postgresql

我希望有一个随机字符串的sha用于列的默认值。

所以,在我的迁移中,我有:

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

然而我实际上无法生产任何东西,我使用了反引号,引号等。从我看过的例子看来,pg函数似乎只适用于SELECT语句。

这是准确的吗?有关如何实现这一目标的任何想法?

由于

2 个答案:

答案 0 :(得分:5)

Rails会尝试解释这个:

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

Ruby代码和:default => md5(...)在Ruby中没有任何意义。如果你引用它,那么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中没有提及新的默认值。如果你想要一个可用的模式,那么你当然必须将Rails推开并使用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,你假装数据库是一个愚蠢的电子表格,并使用可能的before_create钩子在Ruby中做所有事情。或者你可以找到一个比ActiveRecord更少数据库恶意的ORM;我不确定其他ORM如何处理非常量列默认值。

或者,您可以尝试编写BEFORE INSERT触发器,如果​​NEW.uniqueid IS NULL将默认值分配给列。

答案 1 :(得分:3)

您也可以

t.string :token, default: -> { "md5((random())::text)" }, null: false

编辑:即使生成32位数字的随机字符串,也不意味着它是唯一的。我以为是这样,但是我只是遇到了一个独特的索引错误。