Rails миграция: возможно ли update_all с динамическим кодом? - PullRequest
1 голос
/ 30 сентября 2011

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

Мое новое поле «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 ]

4 голосов
/ 30 сентября 2011

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

3 голосов
/ 30 сентября 2011

Для 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
...