ruby-on-rails rails php - ¿Cómo puedo evitar ejecutar callbacks de ActiveRecord?




13 Answers

Esta solución es Rails 2 solamente.

Acabo de investigar esto y creo que tengo una solución. Hay dos métodos privados de ActiveRecord que puede usar:

update_without_callbacks
create_without_callbacks

Tendrás que usar enviar para llamar a estos métodos. ejemplos:

p = Person.new(:name => 'foo')
p.send(:create_without_callbacks)

p = Person.find(1)
p.send(:update_without_callbacks)

Esto es definitivamente algo que solo querrá usar realmente en la consola o mientras hace algunas pruebas al azar. ¡Espero que esto ayude!

includes sql

Tengo algunos modelos que tienen callbacks after_save. Por lo general, eso está bien, pero en algunas situaciones, como cuando se crean datos de desarrollo, quiero guardar los modelos sin ejecutar las devoluciones de llamadas. ¿Hay una manera simple de hacer eso? Algo parecido a ...

Person#save( :run_callbacks => false )

o

Person#save_without_callbacks

Busqué en los documentos de Rails y no encontré nada. Sin embargo, en mi experiencia, los documentos de Rails no siempre cuentan toda la historia.

ACTUALIZAR

Encontré una publicación de blog que explica cómo puedes eliminar devoluciones de llamada de un modelo como este:

Foo.after_save.clear

No pude encontrar dónde está documentado ese método, pero parece funcionar.




Actualizado:

La solución de @Vikrant Chaudhary parece mejor:

#Rails >= v3.1 only
@person.update_column(:some_attribute, 'value')
#Rails >= v4.0 only
@person.update_columns(attributes)

Mi respuesta original:

vea este enlace: ¿Cómo omitir las devoluciones de llamada de ActiveRecord?

en Rails3,

supongamos que tenemos una definición de clase:

class User < ActiveRecord::Base
  after_save :generate_nick_name
end 

Enfoque1:

User.send(:create_without_callbacks)
User.send(:update_without_callbacks)

Approach2: cuando quiera omitirlos en sus archivos rspec o lo que sea, intente esto:

User.skip_callback(:save, :after, :generate_nick_name)
User.create!()

NOTA: una vez hecho esto, si no está en el entorno rspec, debe restablecer las devoluciones de llamada:

User.set_callback(:save, :after, :generate_nick_name)

funciona bien para mí en los carriles 3.0.5




Puede intentar algo como esto en su modelo de persona:

after_save :something_cool, :unless => :skip_callbacks

def skip_callbacks
  ENV[RAILS_ENV] == 'development' # or something more complicated
end

EDITAR: after_save no es un símbolo, pero esa es al menos la milésima vez que intento convertirlo en uno.




Puedes usar update_columns :

User.first.update_columns({:name => "sebastian", :age => 25})

Actualiza los atributos dados de un objeto, sin llamar a guardar, por lo tanto omitiendo validaciones y devoluciones de llamada.




Parece que una forma de manejar esto en Rails 2.3 (ya que update_without_callbacks se ha ido, etc.) sería usar update_all, que es uno de los métodos que omite las devoluciones de llamadas según la guides.rubyonrails.org/… .

Además, tenga en cuenta que si está haciendo algo en su devolución de llamada after_, que hace un cálculo basado en muchas asociaciones (es decir, has_many assoc, donde también acepta accept_nested_attributes_for), tendrá que volver a cargar la asociación, en el caso como parte del guardado , uno de sus miembros fue eliminado.




La respuesta más up-voted puede parecer confusa en algunos casos.

Puede usar simplemente una verificación simple if desea omitir una devolución de llamada, como esta:

after_save :set_title, if: -> { !new_record? && self.name_changed? }



# for rails 3
  if !ActiveRecord::Base.private_method_defined? :update_without_callbacks
    def update_without_callbacks
      attributes_with_values = arel_attributes_values(false, false, attribute_names)
      return false if attributes_with_values.empty?
      self.class.unscoped.where(self.class.arel_table[self.class.primary_key].eq(id)).arel.update(attributes_with_values)
    end
  end



Escribí un complemento que implementa update_without_callbacks en Rails 3:

http://github.com/dball/skip_activerecord_callbacks

La solución correcta, creo, es reescribir sus modelos para evitar devoluciones de llamadas en primer lugar, pero si eso no es práctico en el corto plazo, este complemento puede ayudar.




Cuando necesito un control total sobre la devolución de llamada, creo otro atributo que se usa como un interruptor. Simple y efectivo:

Modelo:

class MyModel < ActiveRecord::Base
  before_save :do_stuff, unless: :skip_do_stuff_callback
  attr_accessor :skip_do_stuff_callback

  def do_stuff
    puts 'do stuff callback'
  end
end

Prueba:

m = MyModel.new()

# Fire callbacks
m.save

# Without firing callbacks
m.skip_do_stuff_callback = true
m.save

# Fire callbacks again
m.skip_do_stuff_callback = false
m.save



Puedes usar la gema sneaky-save: https://rubygems.org/gems/sneaky-save .

Tenga en cuenta que esto no puede ayudar a guardar asociaciones junto sin validaciones. Lanza el error 'created_at no puede ser nulo' ya que inserta directamente la consulta SQL a diferencia de un modelo. Para implementar esto, necesitamos actualizar todas las columnas generadas automáticamente de db.




¿Por qué querrías poder hacer esto en desarrollo? Seguramente, esto significará que está creando su aplicación con datos no válidos y, como tal, se comportará de forma extraña y no como espera en la producción.

Si quieres llenar tu db dev con datos, un mejor enfoque sería construir una tarea de rake que use la gema faker para compilar datos válidos e importarlos en el archivo db creando tantos o tan pocos registros como desees, pero si eres un tacón empeñado en eso y tengo una buena razón, supongo que update_without_callbacks y create_without_callbacks funcionarán bien, pero cuando trates de doblar los rieles a tu voluntad, pregúntate a ti mismo que tienes una buena razón y si lo que estás haciendo es realmente una buena idea.




Otra forma sería usar los ganchos de validación en lugar de las devoluciones de llamada. Por ejemplo:

class Person < ActiveRecord::Base
  validate_on_create :do_something
  def do_something
    "something clever goes here"
  end
end

De esta forma, puede obtener el elemento do_algo por defecto, pero puede anularlo fácilmente con:

@person = Person.new
@person.save(false)



No es la manera más limpia, pero podría envolver el código de devolución de llamada en una condición que verifique el entorno de Rails.

if Rails.env == 'production'
  ...



Related