Marcio Trindade

Monitorando atributos com Rails

A partir do rails 2.1 ganhamos alguns métodos para monitorar as alterações dos atributos. Com isso você passa a ter um grande ganho de performance para efetuar updates em seus projetos, por que o Rails passa a fazer update somente dos atributos que foram modificados. Vamos ver como isso acontece.

Para os exemplos abaixo vamos supor que eu tenha um model User com os atributos name e email

changed?

console
>> user = User.first 
=> #<User id: 1, name: "Daniel Burns", email: "meuemail@gmail.com">
>> user.changed?
=> false
>> user.name="Marcio Trindade"
=> "Marcio Trindade"
>> user.changed?
=> true
>> user.save
=> true
>> user.changed?
=> false

Como podemos observar no exemplo acima o método changed? retorna verdadeiro se o objeto tem o valor diferente do que está salvo no banco ou falso se o valor for o mesmo.

changed

console
>> user = User.first 
=> #<User id: 1, name: "Daniel Burns", email: "meuemail@gmail.com">
>> user.changed
=> []
>> user.name="Marcio Trindade"
=> "Marcio Trindade"
>> user.changed
=> ["namde"]
>> user.email="marciotrindade@gmail.com"
=> "marciotrindade@gmail.com"
>> user.changed
=> ["namde", "email"]
>> user.save
=> true
>> user.changed?
=> []

Parecido com o método acima este nos retorna um array com os atributos que foram atualizados.

changes

console
>> user = User.first 
=> #<User id: 1, name: "Daniel Burns", email: "meuemail@gmail.com">
>> user.changes
=> {}
>> user.name="Marcio Trindade"
=> "Marcio Trindade"
>> user.changes
=> {"name"=>["Daniel Burns", "Marcio Trindade"]}
>> user.email="marciotrindade@gmail.com"
=> "marciotrindade@gmail.com"
>> user.changes
=> {"name"=>["Daniel Burns", "Marcio Trindade"], "email"=>["meuemail@gmail.com", "marciotrindade@gmail.com"]}
>> user.save
=> true
>> user.changed?
=> {}

Este método retorna um hash sendo a chave o nome do atributo modificado e o valor um array com os atributo de antes e depois da alteração.

attribute_changed?

console
>> user = User.first 
=> #<User id: 1, name: "Daniel Burns", email: "meuemail@gmail.com">
>> user.name_changed?
=> false
>> user.name="Marcio Trindade"
=> "Marcio Trindade"
>> user.name_changed?
=> true

Parecido com o método changed? porém para um atributo específico.

attribute_was

console
>> user = User.first 
=> #<User id: 1, name: "Daniel Burns", email: "meuemail@gmail.com">
>> user.name_was
=> "Daniel Burns"
>> user.name="Marcio Trindade"
=> "Marcio Trindade"
>> user.name_was
=> "Daniel Burns"

Retorna o valor original do atributo (como está no banco de dados). Muito útil para recuperar um objeto pelo atributo, como por exemplo um findbyname no filtro before_save.

attribute_change

console
>> user = User.first 
=> #<User id: 1, name: "Daniel Burns", email: "meuemail@gmail.com">
>> user.name_change
=> nil
>> user.name="Marcio Trindade"
=> "Marcio Trindade"
>> user.name_change
=> ["Daniel Burns", "Marcio Trindade"]

Retorna um array com os valores de antes e depois da alteração para um atributo específico.

attribute_will_change!

console
>> user = User.first 
=> #<User id: 1, name: "Daniel Burns", email: "meuemail@gmail.com">
>> user.name_will_changed!
=> nil
>> user.changes
=> {"name"=>["Daniel Burns", "Daniel Burns"]}

Seta o atributo como alterado e força o seu update no banco de dados.

Estas alteração no Rails já me foram úteis economizando linhas de código para verificar se um atributo havia sido modificado e então fazendo uma nova consulta no banco pra trazer o valor antes da modificação. Valeu Rails por mais esta facilidade.

Você pode ver um video em inglês explicando estes métodos aqui no screencast do Rain Bates