Rails迁移:update_all是否可以使用动态代码?

时间:2011-09-30 09:32:08

标签: mysql ruby-on-rails postgresql rails-migrations update-all

我想在表格中添加一个新字段。

我的用户模型中的新“secret_code”字段应该等于Digest :: SHA1.hexdigest([Time.now,rand] .join)[1..12]。

我要做的是生成一个迁移,将字段添加到表中,并使用(某种)唯一的“secret_code”填充现有用户。

class AddSecretCodeToUsers < ActiveRecord::Migration
  def self.up
    add_column :users, :secret_code, :string
    User.update_all ["secret_code =?", Digest::SHA1.hexdigest([Time.now, rand].join)[1..12]]
  end

  def self.down
    remove_column :users, :secret_code
  end
end

问题是此迁移使用相同的密码填充所有现有用户!

一个解决方案是不使用update_all并运行循环来获取每个用户并向每个用户发送更新,但在这种情况下,我的迁移将非常缓慢。

有没有办法向update_all方法发送“唯一”随机值?

谢谢, 奥古斯托

2 个答案:

答案 0 :(得分:4)

尝试将其更改为Digest::SHA1.hexdigest([Time.now, rand].to_s)但我个人会为上面创建一个rake任务,因为它不是真正的迁移。

你的佣金任务会

User.all.each do |u|
  u.update_attribute(:secret_code, Digest::SHA1.hexdigest([Time.now, rand].to_s))
end

但是,对于您的迁移,我还会将t.string :secret_code, :default => Digest::SHA1.hexdigest([Time.now, rand].to_s) 添加到该属性中,以便将其添加到新创建的记录中。

答案 1 :(得分:3)

对于MySQL,您可以将其放在self.up

connection.execute(%Q{
    update users
    set secret_code = substring(sha1(rand()) from 1 for 12)
})

默认情况下PostgreSQL没有SHA1支持,但它确实有MD5,这可能足够了:

connection.execute(%Q{
    update users
    set secret_code = substring(md5(random()::varchar) from 1 for 12)
})

如果安装了pgcrypto软件包,则可以使用SHA1。

这两个都会让数据库完成所有工作,并避免全面解决整个表的所有开销。如果你想把时间混合在一起,你可以玩一下你的哈希值:

md5(random()::varchar || now()::varchar) -- PostgreSQL
sha(rand()            || now()         ) -- MySQL