开发者

Rails migration: update_all with dynamic code is possible?

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 =?", Dig开发者_如何学Goest::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


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.


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
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜