tutorial rails que ejemplos descargar curso caracteristicas ruby-on-rails ruby

ruby on rails - rails - after_commit para un atributo



ruby on rails tutorial (6)

Estoy usando un after_commit en mi aplicación.

Me gustaría que se active solo cuando se actualiza un campo en particular en mi modelo. ¿Alguien sabe cómo hacer eso?


Este es un problema muy antiguo, pero la solución previous_changes aceptada simplemente no es lo suficientemente robusta. En una transacción de ActiveRecord , hay muchas razones por las que puede guardar un Modelo dos veces. previous_changes solo refleja el resultado del último save . Considera este ejemplo

class Test < ActiveRecord::Base after_commit: :after_commit_test def :after_commit_test puts previous_changes.inspect end end test = Test.create(number: 1, title: "1") test = Test.find(test.id) # to initialize a fresh object test.transaction do test.update(number: 2) test.update(title: "2") end

qué salidas:

{"title"=>["1", "2"], "updated_at"=>[...]}

pero, lo que necesitas es:

{"title"=>["1", "2"], "number"=>[1, 2], "updated_at"=>[...]}

Entonces, mi solución es esta:

module TrackSavedChanges extend ActiveSupport::Concern included do # expose the details if consumer wants to do more attr_reader :saved_changes_history, :saved_changes_unfiltered after_initialize :reset_saved_changes after_save :track_saved_changes end # on initalize, but useful for fine grain control def reset_saved_changes @saved_changes_unfiltered = {} @saved_changes_history = [] end # filter out any changes that result in the original value def saved_changes @saved_changes_unfiltered.reject { |k,v| v[0] == v[1] } end private # on save def track_saved_changes # maintain an array of ActiveModel::Dirty.changes @saved_changes_history << changes.dup # accumulate the most recent changes @saved_changes_history.last.each_pair { |k, v| track_saved_change k, v } end # v is an an array of [prev, current] def track_saved_change(k, v) if @saved_changes_unfiltered.key? k @saved_changes_unfiltered[k][1] = track_saved_value v[1] else @saved_changes_unfiltered[k] = v.dup end end # type safe dup inspred by http://.com/a/20955038 def track_saved_value(v) begin v.dup rescue TypeError v end end end

que puedes probar aquí: github.com/ccmcbeck/after-commit


No creo que puedas hacerlo en after_commit

Se llama al after_commit después de que la transacción se haya comprometido. Rails Transactions

Por ejemplo en mi consola de rieles

> record = MyModel.find(1) => #<MyModel id: 1, label: "test", created_at: "2011-08-19 22:57:54", updated_at: "2011-08-19 22:57:54"> > record.label = "Changing text" => "Changing text" > record.label_changed? => true > record.save => true > record.label_changed? => false

Por lo tanto, no podrá usar la condición :if en after_commit porque el atributo ya no se marcará como cambiado ya que se ha guardado. ¿Es necesario que rastree si el campo que busca ha changed? en otra devolución de llamada antes de que se guarde el registro?


Parece que quieres algo así como una devolución de llamada condicional . Si hubiera publicado algún código, podría haberlo señalado en la dirección correcta; sin embargo, creo que le gustaría usar algo como esto:

after_commit :callback, :if => Proc.new { |record| record.field_modified? }


Una vieja pregunta, pero este es un método que he encontrado que podría funcionar con la devolución de llamada after_commit (trabajando en la respuesta de paukul ). Al menos, los valores persisten después de la confirmación en IRB.

after_commit :callback, if: proc { |record| record.previous_changes.key?(:attribute) && record.previous_changes[:attribute].first != record.previous_changes[:attribute].last }


Usa gem ArTransactionChanges . previous_changes no funciona para mí en Rails 4.0.x

Uso:

class User < ActiveRecord::Base include ArTransactionChanges after_commit :print_transaction_changes def print_transaction_changes transaction_changed_attributes.each do |name, old_value| puts "attribute #{name}: #{old_value.inspect} -> #{send(name).inspect}" end end end


Respondiendo a esta vieja pregunta porque aún aparece en los resultados de búsqueda

puede usar el método previous_changes que devuelve un hash del formato:

{"changed_attribute" => ["valor antiguo", "valor nuevo"]}

es lo que changes hasta que el registro se guarda realmente (desde active_record / attribute_methods / dirty.rb):

def save(*) #:nodoc: if status = super @previously_changed = changes @changed_attributes.clear # .... whatever goes here

entonces en tu caso puedes verificar por previous_changes.key? "your_attribute" previous_changes.key? "your_attribute" o algo así