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?
>> 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
>> 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
>> 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?
>> 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
>> 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 find_by_name no filtro before_save.
attribute_change
>> 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!
>> 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
Por que nao:)