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

发布于 2024-12-07 12:19:31 字数 637 浏览 2 评论 0原文

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

我的用户模型中的新“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 方法?

谢谢, 奥古斯托

I'd like to add a new field in a table.

My new "secret_code" field in my User model should be equal to Digest::SHA1.hexdigest([Time.now, rand].join)[1..12].

What I'm trying to do is generate a migration that would add the field to the table and also populate my existing users with a (sort of) unique "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

The problem is that this migration populate all the existing users with the same secret code!

One solution would be NOT to use update_all and run a loop to fetch every user and send an update to each one, but in this case my migration would be extremely slow.

Is there a way to send a "unique" random value to an update_all method?

Thanks,
Augusto

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

忆沫 2024-12-14 12:19:31

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

您的 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 =>摘要::SHA1.hexdigest([Time.now, rand].to_s)
添加到属性中,以便将其添加到新创建的记录上。

Try changing it to Digest::SHA1.hexdigest([Time.now, rand].to_s) but personally I'd create a rake task to the above as it's not really a migration.

Your rake task would do

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

However, for your migration I'd also add t.string :secret_code, :default => Digest::SHA1.hexdigest([Time.now, rand].to_s)
to the attribute so that it is added on newly created records.

筑梦 2024-12-14 12:19:31

对于 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

For MySQL, you could throw this right in your self.up:

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

PostgreSQL doesn't have SHA1 support by default but it does have MD5 and that's probably good enough for this:

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

If you have the pgcrypto package installed then you could use SHA1 for both.

Both of those will let the database do all the work and avoid all the overhead of round-tripping your whole table. You can play around with what you hash a bit as well, if you wanted to mix the time in:

md5(random()::varchar || now()::varchar) -- PostgreSQL
sha(rand()            || now()         ) -- MySQL
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文