ruby on rails - rails - Rieles: actualice el atributo de modelo sin invocar devoluciones de llamada
rails before_update (9)
Algunas opciones de cómo hacer esto en rails4 http://edgeguides.rubyonrails.org/active_record_callbacks.html#skipping-callbacks
Tengo un modelo de usuario que tiene un atributo: credits. Quiero un botón simple que agregará 5 a los créditos del usuario, a través de una ruta llamada "agregar" para que / users / 3 / add agregue 5 a los créditos de id de usuario = 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 @ user.save porque tengo una devolución de llamada before_save que vuelve a encriptar la contraseña del usuario en función de la hora UTC actual. Simplemente quiero agregar 5 al atributo y evitar la devolución de llamada, nunca pensé que una cosa tan simple pudiera 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
EDICION 2:
Ok, fue un problema de validación que hizo que los cambios en "EDITAR" no funcionaran, ¡pero aún me encantaría una respuesta a la pregunta original de actualización sin devoluciones de llamada!
Como respuesta general, en Rails 4 esta es una manera simple de actualizar atributos sin activar devoluciones de llamada:
@user.update_column ''credits'', 5
Si necesita actualizar múltiples atributos sin devoluciones de llamada de triggers:
@user.update_columns credits: 5, bankrupt: false
Aquí hay otras opciones http://edgeguides.rubyonrails.org/active_record_callbacks.html#skipping-callbacks si lo prefiere, pero me pareció que esta era la más fácil.
Creo que deberías usar el método update_counters en este caso. Úselo así en su acción de controlador:
def add
User.update_counters params[:id], :credits => 5
redirect_to root_path
end
Debería poder usar update_all para evitar la activación de 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.
Para actualizar múltiples atributos sin devolución 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 deseas, incluso puedes probar un método update_columns y mezclar esto con tu clase base de registro activo.
Para actualizar un atributo, puede usar update_column. Además, hay algunos métodos específicos que se pueden encontrar en las guías de rieles http://guides.rubyonrails.org/active_record_callbacks.html#skipping-callbacks
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. Muy guay.
Rails 3.1 introdujo update_column
, que es lo mismo que update_attribute
, pero sin activar validaciones o callbacks:
http://apidock.com/rails/ActiveRecord/Persistence/update_column
Tal vez su otro hook before_save debería verificar si la contraseña del usuario realmente ha cambiado antes de encriptarla nuevamente.
Usted tiene una cantidad de opciones, que incluyen cambiar la devolución de llamada que usa, por ejemplo, after_create
.
Puede actualizar las columnas sin activar las devoluciones de llamada; consulte http://guides.rubyonrails.org/active_record_callbacks.html#skipping-callbacks devoluciones de http://guides.rubyonrails.org/active_record_callbacks.html#skipping-callbacks en la guía de AR. Por ejemplo, update_column
no update_column
devoluciones de llamada. El enlace anterior enumera las funciones no desencadenantes.
También puede usar cualquiera de los formularios de devolución de llamada condicional (o incluso un observador) para cuando se cambie la contraseña. Ver ActiveModel::Dirty , eg, @user.password_changed?
.