Rails миграция: возможно ли update_all с динамическим кодом?

Я хотел бы добавить новое поле в таблицу.

Мое новое поле "secret_code" в моей модели User должно быть равно Digest::SHA1.hexdigest([Time.now, rand].join)[1..12].

Я пытаюсь сгенерировать миграцию, которая добавит поле в таблицу, а также заполнит моих существующих пользователей (своего рода) уникальным "секретным кодом".

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 ответа

Решение

Попробуйте изменить это на Digest::SHA1.hexdigest([Time.now, rand].to_s) но лично я бы создал грабли для вышеперечисленного, поскольку это не совсем миграция.

Ваша задача с граблями сделает

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) к атрибуту, чтобы он добавлялся во вновь создаваемые записи.

Для 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
Другие вопросы по тегам