Rails update_all с hstore
Какой хороший способ обновить несколько записей в столбцах hstore с помощью activerecord? Прямо сейчас я перебираю, обновляю и сохраняю вот так:
time = Time.now.to_s
scoped_tasks.each do |task|
task.data[:last_checked] = time
task.save!
end
Есть ли способ сделать это с update_all
запрос? Одно решение, которое я видел, выглядит так:
MyModel.update_all(:properties => ActiveRecord::Coders::Hstore.dump({'a' => 1}))
Но проблема в том, что он перезаписывает весь столбец, поэтому другие значения теряются. Я также видел это:
MyModel.update_all("data = data || hstore('a', 'blah')")
Но почему-то я возвращаюсь 0
для значения. Похоже, что это будет работать только в том случае, если магазин пуст.
2 ответа
Я сам боролся с тем же вопросом, вот как я смог его решить:
MyModel.update_all([%(data = data || hstore(?,?)), 'a', 'new_value']))
Основным исправлением для этого было обертывание действия update_all в [] и%(). Я все еще пытаюсь выяснить, как% () определяет SET в Postgre SQL, так что если у кого-нибудь есть объяснение, которое будет очень полезным.
В моем случае я тоже фактически удалял ключ (на самом деле я хотел обновить имя ключа, но сохранить значение). Так что, если у кого-то есть такая проблема, код выглядит так:
MyModel.update_all([%(data = delete("data",?)), 'a'])
Я надеялся выполнить оба действия в одном вызове, но это создавало действительно странную команду в SQL, где второе действие было добавлено как часть предложения WHERE, а не SET. Все еще немного черной магии для меня, но, надеюсь, это поможет...
Если вы используете
MyModel.update_all(:properties => ActiveRecord::Coders::Hstore.dump({'a' => 1}))
тогда он будет очищен от других значений, и если вы попытаетесь использовать
MyModel.update_all("data = data || hstore('a', 'blah')")
это будет работать, только если в столбце hstore есть какое-либо значение, поэтому попробуйте использовать комбинацию обоих
if (hstore_column_name).present?
MyModel.update_all("data = data || hstore('a', 'blah')")
else
MyModel.update_all(:properties => ActiveRecord::Coders::Hstore.dump({'a' => 1}))