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 --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
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 On 3/6/07, Don.Mc <Don.McClean-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:> > > 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 > > > > >--~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
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 Norris <sconds-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:> 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 > > On 3/6/07, Don.Mc <Don.McClean-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org > wrote: > > > > 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 > >-- Colin Strasser Union Square Internet Development 917.723.6930 (m) 646.219.0332 (f) --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
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 On 3/7/07, Colin Strasser <colin-BOTN+IkIZYQ@public.gmane.org> wrote:> > > 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 Norris <sconds-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote: > > 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 > > > > On 3/6/07, Don.Mc <Don.McClean-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org > wrote: > > > > > > 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 > > > > > -- > Colin Strasser > Union Square Internet Development > 917.723.6930 (m) > 646.219.0332 (f) > > > >--~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
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. On Mar 7, 10:25 am, "Russell Norris" <sco...-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:> 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 > > On 3/7/07, Colin Strasser <c...-BOTN+IkIZYQ@public.gmane.org> wrote: > > > > > 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 Norris <sco...-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote: > > > 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 > > > > On 3/6/07, Don.Mc <Don.McCl...-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org > wrote: > > > > > 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 > > > -- > > Colin Strasser > > Union Square Internet Development > > 917.723.6930 (m) > > 646.219.0332 (f)--~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
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 On 3/7/07, Colin Strasser <colin-BOTN+IkIZYQ@public.gmane.org> wrote:> > > 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 Norris <sconds-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote: > > 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 > > > > On 3/6/07, Don.Mc <Don.McClean-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org > wrote: > > > > > > 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 > > > > > -- > Colin Strasser > Union Square Internet Development > 917.723.6930 (m) > 646.219.0332 (f) > > > >--~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---