ruby on rails 3 - new - Pista sucia para atributos no persistentes en un objeto ActiveRecord en rieles
ruby on rails mvc (3)
Descubrí una solución que funcionó para mí ...
Guarde este archivo como lib/active_record/nonpersisted_attribute_methods.rb
: https://gist.github.com/4600209
Entonces puedes hacer algo como esto:
require ''active_record/nonpersisted_attribute_methods''
class Foo < ActiveRecord::Base
include ActiveRecord::NonPersistedAttributeMethods
define_nonpersisted_attribute_methods [:bar]
end
foo = Foo.new
foo.bar = 3
foo.bar_changed? # => true
foo.bar_was # => nil
foo.bar_change # => [nil, 3]
foo.changes[:bar] # => [nil, 3]
Sin embargo, parece que recibimos una advertencia cuando lo hacemos de esta manera:
DEPRECATION WARNING: You''re trying to create an attribute `bar''. Writing arbitrary attributes on a model is deprecated. Please just use `attr_writer` etc.
Así que no sé si este enfoque se romperá o será más difícil en Rails 4 ...
Tengo un objeto que se hereda de ActiveRecord, pero tiene un atributo que no se conserva en la base de datos, como:
class Foo < ActiveRecord::Base
attr_accessor :bar
end
Me gustaría poder realizar un seguimiento de los cambios en ''bar'', con métodos como ''bar_changed?'', Según lo provisto por ActiveModel Dirty. El problema es que cuando intento implementar Dirty en este objeto, como se describe en los docs , define_attribute_methods
un error, ya que tanto ActiveRecord como ActiveModel han definido define_attribute_methods
, pero con un número diferente de parámetros, por lo que recibo un error cuando tratando de invocar define_attribute_methods [:bar]
.
He intentado define_attribute_methods
alias define_attribute_methods
antes de incluir ActiveModel::Dirty
, pero sin suerte: define_attribute_methods
un error de método no definido.
¿Alguna idea sobre cómo lidiar con esto? Por supuesto, podría escribir los métodos requeridos manualmente, pero me preguntaba si sería posible utilizar los módulos Rails, extendiendo la funcionalidad de ActiveModel a los atributos que no controla ActiveRecord.
Escriba la barra = método usted mismo y use una variable de instancia para rastrear los cambios.
def bar=(value)
@bar_changed = true
@bar = value
end
def bar_changed?
if @bar_changed
@bar_changed = false
return true
else
return false
end
end
Estoy usando el attribute_will_change!
Método y las cosas parecen estar funcionando bien.
Es un método privado definido en active_model/dirty.rb
, pero ActiveRecord lo mezcla en todos los modelos.
Esto es lo que terminé implementando en mi clase modelo:
def bar
@bar ||= init_bar
end
def bar=(value)
attribute_will_change!(''bar'') if bar != value
@bar = value
end
def bar_changed?
changed.include?(''bar'')
end
El método init_bar
solo se utiliza para inicializar el atributo. Puede o no puede necesitarlo.
No tuve que especificar ningún otro método (como define_attribute_methods
) ni incluir ningún módulo. Tiene que volver a implementar algunos de los métodos usted mismo, pero al menos el comportamiento será mayormente consistente con ActiveModel.
Admito que todavía no lo he probado a fondo, pero hasta ahora no he encontrado ningún problema.