Estoy usando un after_commit en mi aplicación.after_commit para un atributo
Me gustaría que se active solo cuando se actualiza un campo en particular en mi modelo. ¿Alguien sabe cómo hacer eso?
Estoy usando un after_commit en mi aplicación.after_commit para un atributo
Me gustaría que se active solo cuando se actualiza un campo en particular en mi modelo. ¿Alguien sabe cómo hacer eso?
Parece que quiere algo como un conditional callback. Si usted había publicado algún código te podría haber apuntado en la dirección correcta sin embargo, creo que se quiere usar algo como esto:
after_commit :callback,
:if => Proc.new { |record| record.field_modified? }
no creo que pueda hacerlo en after_commit
El after_commit se llama después de la transacción se compromete Rails Transactions
Por ejemplo, en mi consola 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 posible que necesite rastrear si el campo que está buscando es changed?
en otra devolución de llamada antes de guardar el registro?
Para responder a esta cuestión de edad, ya que todavía aparece en los resultados de búsqueda
puede utilizar el método previous_changes cuales returnes un hash del formato:
{ "changed_attribute" => [ "valor antiguo ", "nuevo valor"]}
es lo changes fue hasta que el registro se guarda realmente (de active_record/attribute_methods/dirty.rb):
def save(*) #:nodoc:
if status = super
@previously_changed = changes
@changed_attributes.clear
# .... whatever goes here
por lo que en su caso puede comprobar para previous_changes.key? "your_attribute"
o algo por el estilo
pregunta antiguo, pero esto es un método que he encontrado que podría trabajar con la devolución de llamada after_commit (trabajando fuera paukul's answer). 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
}
Según [documentación] (http://apidock.com/rails/ActiveModel/Dirty/previous_changes), creo que 'keys' debe llamarse:' record.previous_changes.keys.include? (: Attribute) '. Con este cambio, funciona para mí. – milkfarm
'record.previous_changes.key? (: Attribute)' es condición suficiente, porque el primer y el último valor no siempre son iguales. –
@jamesdevar tiene razón, pero esta solución puede fallar si su modelo se guarda más de una vez durante la transacción. Aquí hay un ejemplo del proyecto de Rails https://github.com/ccmcbeck/after-commit para demostrar el problema y la solución para solucionarlo. –
Use gem ArTransactionChanges. previous_changes
no está funcionando 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
Este es un problema muy antiguo, pero la solución aceptada previous_changes
simplemente no es lo suficientemente robusta. En una transacción ActiveRecord
, hay muchas razones por las que puede guardar un Modelo dos veces. previous_changes
solo refleja el resultado del save
final.Considere 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
que da salida:
{"title"=>["1", "2"], "updated_at"=>[...]}
pero, lo que necesita es:
{"title"=>["1", "2"], "number"=>[1, 2], "updated_at"=>[...]}
Por lo tanto, mi solución es la siguiente:
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://stackoverflow.com/a/20955038
def track_saved_value(v)
begin
v.dup
rescue TypeError
v
end
end
end
que se puede probar aquí: https://github.com/ccmcbeck/after-commit
¿está modificado el campo? un método prefabricado o este es un método que tendré que escribir para verificar el valor del campo? Básicamente, estoy tratando de recalcular y guardar la calificación de un usuario en base a todas sus calificaciones de citas. una calificación para una cita se puede agregar después de que se haya creado, entonces me gustaría saber si el campo de calificación se actualizó aquí está algo del código estoy trabajando con clase Cita
alik
Nop comprobar el valor del campo. –