Rails: Actualizar atributo de modelo sin invocar callbacks
Tengo un modelo de usuario que tiene un atributo :credits. Quiero un botón simple que agregue 5 a los créditos del usuario, a través de una ruta llamada "add" para que /users/3/add agregue 5 a los créditos de user id = 3.
def add
@user = User.find(params[:id])
@user.credits += 5
redirect_to root_path
end
Esa es la parte relevante de mi controlador. El problema es que no quiero llamar a @usuario.guardar porque tengo una devolución de llamada before_save que vuelve a cifrar la contraseña del usuario en función de la hora UTC actual. Solo quiero simplemente añadir 5 al atributo y evitar el callback, nunca pensé que una cosa tan simple podría ser tan difícil.
EDITAR:
Cambié la devolución de llamada a: before_create, aquí está mi nuevo código de controlador (parte relevante):
def add
@user = User.find(params[:id])
@user.add_credits(5)
@user.save
flash[:success] = "Credits added!"
redirect_to root_path
end
Y aquí está mi código en el modelo:
def add_credits(num)
self.credits = num
end
EDITAR 2:
Ok fue un problema de validación que hizo que los cambios en "EDITAR" no funcionaran, pero todavía me encantaría una respuesta a la pregunta original de actualizar sin devoluciones de llamada!
9 answers
Rails 3.1 introducido update_column
, que es lo mismo que update_attribute
, pero sin activar validaciones o devoluciones de llamada:
Http://apidock.com/rails/ActiveRecord/Persistence/update_column
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-12-28 22:54:36
Para actualizar múltiples atributos sin devoluciones de llamada, puede usar update_all en su modelo de la siguiente manera:
self.class.update_all({name: value, name: value}, self.class.primary_key => id)
Si realmente lo desea, puede probar incluso un método update_columns y mezclar esto con su clase base active record.
Para actualizar un atributo puede usar update_column. Además hay algunos métodos específicos que se pueden encontrar en las guías rails http://guides.rubyonrails.org/active_record_callbacks.html#skipping-callbacks
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-04-22 09:06:25
Creo que deberías usar el método update_counters en este caso. Úsalo así en la acción del controlador:
def add
User.update_counters params[:id], :credits => 5
redirect_to root_path
end
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-12-28 04:50:19
Como respuesta general, en Rails 4 esta es una forma sencilla de actualizar atributos sin activar callbacks:
@user.update_column 'credits', 5
Si necesita actualizar varios atributos sin disparadores callbacks:
@user.update_columns credits: 5, bankrupt: false
Hay otras opciones aquí en las Guías Rails si lo prefieres, pero encontré que esta manera es la más fácil.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-08-06 20:03:11
Debería ser capaz de usar update_all para evitar desencadenar devoluciones de llamada.
def add
@user = User.find(params[:id])
User.where(:id=>@user.id).update_all(:credits => @user.credits+5)
redirect_to root_path
end
Preferiría poner esta lógica en el modelo, pero esto debería funcionar para resolver su problema original como se especifica en el controlador.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-12-28 04:22:42
Algunas opciones para hacer esto en rails4 http://edgeguides.rubyonrails.org/active_record_callbacks.html#skipping-callbacks
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-12-09 20:25:18
Para mongoid, terminé usando http://mongoid.org/en/mongoid/docs/persistence.html Específicamente, puedes usar:
person.set(name:"Robert Pulson")
Y no se emitirá devolución de llamada. Qué guay.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-06-19 18:35:58
Tal vez su otro gancho before_save debería verificar si la contraseña del usuario realmente ha cambiado antes de cifrarla nuevamente.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-12-28 01:41:38
Tiene varias opciones, incluyendo cambiar qué devolución de llamada usa, por ejemplo, after_create
.
Puede actualizar columnas sin activar callbacks, consulte Omitir Callbacks en la guía AR. Por ejemplo, update_column
no activa devoluciones de llamada. El enlace anterior enumera las funciones que no activan.
También puede usar cualquiera de los formularios de Callback Condicional (o incluso un observador) para cuando se cambie la contraseña. Ver ActiveModel::Dirty, por ejemplo, @user.password_changed?
.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-03-22 11:45:50