Forum: Ruby on Rails Clean way to detect change using callbacks

Announcement (2017-05-07): is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see and for other Rails- und Ruby-related community platforms.
Aeac27d9f81191536d3c86ee825d71b2?d=identicon&s=25 Don Mc (dmcclean)
on 2007-03-06 22:34
(Received via mailing list)
I would like in my 'after_update' callback to detect if an attribute
has been
changed, and if so change some related objects. Is the best way
something like this

class Thing < ActiveRecord::Base

def before_update
  @old = Thing.find(

end after_update
  if @old.val != self.val

Or is there a better way? I wish I could avoid the 'find' call if

Thanks in advance,
Don Mc
70225136eacd3d870f64e03bff678655?d=identicon&s=25 Russell Norris (Guest)
on 2007-03-07 14:59
(Received via mailing list)
What I've done is handle this from the controller, something like this:

class TheController < ActionController
  def update
    @thing = Thing.find(params[:id]) rescue nil
    redirect_to X unless @thing # Where X = named route or routing hash
[controller, action, etc]
    old = {}
    old[:name] =
    old[:body] = @thing.body
    # Process @thing
    if != old[:name]
      # Do whatcha gotta do...
    if @thing.body != old[:body]
      # You get the picture...

Don't just make a dup of @thing, though. 'Cause when @
thing.update_attributes(params[:thing]) gets called it will change old
well due to Ruby's shallow copying. You could marshal the whole object
I've found it easier to just copy specific attributes. I like the
old[:attribute] method but it'd work the same with separate variables
each, like old_name =, etc.

Hope that helps.

A5c5da3240c5ddd0ab2eb8546478726e?d=identicon&s=25 Colin Strasser (Guest)
on 2007-03-07 15:59
(Received via mailing list)
I prefer the OP's instinct to handle the dependencies within the
model.  It's centralized for all users of the model (i.e.,
controllers), easier to test and better encapsulated.  That said, I
think the Rails way to deal with this is to override the default
setter method for the attribute.

class Thing < ActiveRecord::Base
  def val=(v)
    write_attribute(:val, v)
    do_stuff # Operations that depend on new val

This is also independent of whether the Thing is ever written to the
DB, which is generally what you want.



On 3/7/07, Russell Norris <> wrote:
>     old[:body] = @thing.body
> Don't just make a dup of @thing, though. 'Cause when
> On 3/6/07, Don.Mc < > wrote:
> > end
> >
> > Thanks in advance,
> > Don Mc
> >

Colin Strasser
Union Square Internet Development
917.723.6930 (m)
646.219.0332 (f)
70225136eacd3d870f64e03bff678655?d=identicon&s=25 Russell Norris (Guest)
on 2007-03-07 17:31
(Received via mailing list)
Will this work for things like calling a sweeper if the url of a page
changes? It's been a while but I remember having one heck of a time
ActiveRecord models to communicate with their controllers that way. But
it's been a while and B) I only half know what I'm doing know and
less back then.

Oh yeah, and what's the OP?

Aeac27d9f81191536d3c86ee825d71b2?d=identicon&s=25 Don Mc (dmcclean)
on 2007-03-07 22:28
(Received via mailing list)
Thanks for responding!

In this particular case, I really don't want to update the related
objects unless the object has been
saved, since the related objects are in the database also.

Thats a good point about the shallow copying issue.I would like to
leave the
operation in the model, to handle updates from different sources.
70225136eacd3d870f64e03bff678655?d=identicon&s=25 Russell Norris (Guest)
on 2007-03-11 18:27
(Received via mailing list)
I just wanted to thank you for drawing my attention to this methodology.
I've done some further looking into it and it will indeed do exactly the
kind of things I need. What I ended up doing was something like

class Thing < ActiveRecord::Base
  attr_reader old_name

  def name=(val)
    @old_name = (val == name) ? nil : name
    super val

  def vitals_changed?
    @old_name ? true : false

then checking @ thing.vitals_changed? which works marvelously. I
cannot thank you enough. This really helps clean up some rather sticky,
messy, and misplaced code fragments in my app. Thanks, thanks, thanks.

This topic is locked and can not be replied to.