2011-12-28 17 views
52

Tengo un modelo de usuario que tiene un atributo: credits. Quiero un simple botón que agregará 5 a créditos del usuario, a través de una ruta llamada "añadir" para que/usuarios/3/agregar sumaría 5 a los créditos del identificador de usuario = 3.Rieles: Actualizar atributo de modelo sin invocar callbacks

def add 
    @user = User.find(params[:id]) 
    @user.credits += 5 
    redirect_to root_path 
end 

Eso 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.

EDIT:

He cambiado la devolución de llamada: before_create, aquí es mi nuevo código del controlador (parte pertinente):

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 

EDIT 2:

Ok, era 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 actualizar sin devoluciones de llamada.

+0

Proporcioné un enlace con una lista de los métodos que no desencadenan devoluciones de llamada, y tanto Finbarr como yo sugerimos utilizar una devolución de llamada condicional: ¿qué soluciones adicionales está buscando? –

Respuesta

1

Tal vez su otro hook before_save debería verificar si la contraseña del usuario realmente ha cambiado antes de encriptarla nuevamente.

1

Tiene varias opciones, incluido el cambio de la devolución de llamada que utiliza, por ejemplo, after_create.

Puede actualizar las columnas sin activar devoluciones de llamada; consulte Skipping Callbacks en la guía de AR. Por ejemplo, update_column no activa las devoluciones de llamada. El enlace anterior enumera las funciones no desencadenantes.

También puede utilizar cualquiera de los formularios Conditional Callback (o incluso un observador) para cuando se cambie la contraseña. Ver ActiveModel::Dirty, por ejemplo, @user.password_changed?.

+0

Ok, lo cambié a "after_create" pero aún no funciona. Ver mi edición para mi nuevo código, no puedo obtener créditos para cambiar. –

+0

@hatboysam Bueno, hace algo diferente: antes de agregar, ahora estás configurando. Use 'save!' Para ver si hay una excepción (y/o revise los registros y/o elimine los silenciadores de backtrace). –

2

Debe poder usar update_all para evitar la activación de devoluciones de llamadas.

def add 
@user = User.find(params[:id]) 
User.where(:id=>@user.id).update_all(:credits => @user.credits+5) 
redirect_to root_path 
end 

prefiero poner esta lógica en el modelo, pero esto debería trabajar para resolver su problema original como spec'da en el controlador.

2

Creo que debería usar el método update_counters en este caso. Utilizar de esta manera en su acción de controlador:

def add 
    User.update_counters params[:id], :credits => 5 
    redirect_to root_path 
end 
+0

update_counters/increment_counter también funcionan con 2.x nice! – rogerdpack

5

Para actualizar varios 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 real Lo que quiero es que incluso puedas 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 encuentran en los rieles guías http://guides.rubyonrails.org/active_record_callbacks.html#skipping-callbacks

+1

finalmente una respuesta que funciona con rieles 2.x, ¡gracias! – rogerdpack

2

Para MongoId, yo terminamos utilizando http://mongoid.org/en/mongoid/docs/persistence.html En concreto, puede utilizar:

person.set(name:"Robert Pulson") 

y no se emitirá la devolución de llamada. Muy guay.

+0

su person.set (: nombre, "Robert Pulson") –

+1

@JudeCalimbas no, no es, ArgumentError: número de argumentos incorrectos (dado 2, esperado 1) – rept

1

Como respuesta general, en los carriles 4 esta es una manera sencilla de actualizar atributos sin devoluciones de llamada de activación:

@user.update_column credits:5 

Si necesita actualizar varios atributos sin desencadena devoluciones de llamada:

@user.update_columns credits: 5, bankrupt: false 

Hay son otras opciones here in the Rails Guides si lo prefiere, pero encontré esta manera de ser la más fácil.

+1

user.update_column credits: 5 no funciona. Debería ser user.update_column 'credits', 5 –

+0

Estoy usando Rails 4.2 y esto definitivamente funciona para mí. Esta línea genera la siguiente consulta: usuarios de "ACTUALIZACIÓN" "créditos SET" = $ 1, "updated_at" = $ 2 WHERE "usuarios". "Id" = $ 3 [["credits", 5], ["updated_at", "2017 -04-01 21: 34: 52.746626 "], [" id ", 1]]' – Matt

Cuestiones relacionadas