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(self.id)
end
end after_update
if @old.val != self.val
do_stuff
end
end
Or is there a better way? I wish I could avoid the ‘find’ call if
possible.
Thanks in advance,
Don Mc
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] = @thing.name
old[:body] = @thing.body
# Process @thing
if @thing.name != old[:name]
# Do whatcha gotta do…
end
if @thing.body != old[:body]
# You get the picture…
end
end
end
Don’t just make a dup of @thing, though. 'Cause when @
thing.update_attributes(params[:thing]) gets called it will change old
as
well due to Ruby’s shallow copying. You could marshal the whole object
but
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
for
each, like old_name = @thing.name, etc.
Hope that helps.
RSL
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
end
end
This is also independent of whether the Thing is ever written to the
DB, which is generally what you want.
HTH,
Colin
On 3/7/07, Russell N. [email protected] wrote:
old[:body] = @thing.body
Don’t just make a dup of @thing, though. 'Cause when
On 3/6/07, Don.Mc <[email protected] > wrote:
end
Thanks in advance,
Don Mc
–
Colin Strasser
Union Square Internet Development
917.723.6930 (m)
646.219.0332 (f)
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
getting
ActiveRecord models to communicate with their controllers that way. But
A)
it’s been a while and B) I only half know what I’m doing know and
probably
less back then.
Oh yeah, and what’s the OP?
RSL
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.
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
end
def vitals_changed?
@old_name ? true : false
end
end
then checking @ thing.vitals_changed? which works marvelously. I
seriously
cannot thank you enough. This really helps clean up some rather sticky,
messy, and misplaced code fragments in my app. Thanks, thanks, thanks.
RSL