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