The subject asks the question. Should child callbacks call their parents in STI design models? Right now they don''t and it was causing a headache as we needed to audit in the parent(ie: acts_as_auditable) and another plugin the child, specific to the scope of only that class(ie: acts_as_ldapable). acts_as_ldapable binds to the same callbacks as auditable, before_save, after_save, etc. So basically the child overrided the parents callbacks and neglected to behave normally. I submitted this ticket and patch if its any use to extend this behavior to rails, it would be much appreciated. Thanks. http://dev.rubyonrails.org/ticket/4036 -- -- Adam Ballai <adam.ballai@integrumtech.com> Integrum Technologies, LLC Phone: +1 602 792 1270 x 104 Mobile: +1 602 373 3072 _______________________________________________ Rails-core mailing list Rails-core@lists.rubyonrails.org http://lists.rubyonrails.org/mailman/listinfo/rails-core
On 3/1/06, Adam Ballai <adam.ballai@integrumtech.com> wrote:> The subject asks the question. > > Should child callbacks call their parents in STI design models? > Right now they don''t and it was causing a headache as we needed to audit > in the parent(ie: acts_as_auditable) and another plugin the child, > specific to the scope of only that class(ie: acts_as_ldapable). > > acts_as_ldapable binds to the same callbacks as auditable, before_save, > after_save, etc. > > So basically the child overrided the parents callbacks and neglected to > behave normally. > > I submitted this ticket and patch if its any use to extend this behavior > to rails, it would be much appreciated. Thanks. > > http://dev.rubyonrails.org/ticket/4036 > > -- > -- > Adam Ballai <adam.ballai@integrumtech.com> > Integrum Technologies, LLC > Phone: +1 602 792 1270 x 104 > Mobile: +1 602 373 3072Perhaps plugins shouldn''t be defining those methods, and instead use the callback class methods: class Foo < AR::Base before_save :do_this_one_last_thing protected def do_this_one_last_thing end end Otherwise, this could cause issues for someone overwriting a parent''s callback, expecting to override it completely. -- Rick Olson http://techno-weenie.net
Rick Olson wrote:> Perhaps plugins shouldn''t be defining those methods, and instead use > the callback class methods: > > class Foo < AR::Base > before_save :do_this_one_last_thing > > protected > def do_this_one_last_thing > end > end > > Otherwise, this could cause issues for someone overwriting a parent''s > callback, expecting to override it completely. >Well thats what the plugins _are_ doing in a mix-in form. class_eval do before_save :something end acts_as_auditable sets before_save :something to -> Parent acts_as_ldapable set before_save :something_else to -> Child :something to-> Parent becomes ignored instead of calling the parent as well... before_save is a callback for the observer, but it is still a method, so you will always override it, unless you call super on it. In one way this is proper behavior, but it begs the question, what if we need to do more than one different thing before or after a save and they are different between types in a single table inheritance scheme. Either the design meant to make callbacks overrideable via inheritance, or missed a tiny detail in implementation. -- -- Adam Ballai <adam.ballai@integrumtech.com> Integrum Technologies, LLC Phone: +1 602 792 1270 x 104 Mobile: +1 602 373 3072 _______________________________________________ Rails-core mailing list Rails-core@lists.rubyonrails.org http://lists.rubyonrails.org/mailman/listinfo/rails-core
On 3/1/06, Adam Ballai <adam.ballai@integrumtech.com> wrote:> Rick Olson wrote: > > Perhaps plugins shouldn''t be defining those methods, and instead use > > the callback class methods: > > > > class Foo < AR::Base > > before_save :do_this_one_last_thing > > > > protected > > def do_this_one_last_thing > > end > > end > > > > Otherwise, this could cause issues for someone overwriting a parent''s > > callback, expecting to override it completely. > > > Well thats what the plugins _are_ doing in a mix-in form. > > class_eval do > before_save :something > end > > acts_as_auditable sets before_save :something to -> Parent > acts_as_ldapable set before_save :something_else to -> Child > :something to-> Parent becomes ignored instead of calling the parent as > well... > > before_save is a callback for the observer, but it is still a method, so > you will always override it, unless you call super on it. In one way > this is proper behavior, but it begs the question, what if we need to do > more than one different thing before or after a save and they are > different between types in a single table inheritance scheme. > > Either the design meant to make callbacks overrideable via inheritance, > or missed a tiny detail in implementation. > > -- > -- > Adam Ballai <adam.ballai@integrumtech.com> > Integrum Technologies, LLC > Phone: +1 602 792 1270 x 104 > Mobile: +1 602 373 3072The before_save class method adds the callbacks to an inheritable array, so they should be passed to the subclasses. Unless, of course, your subclass is loaded before the before filter: class Parent < AR::Base belongs_to :child # in Rails 1.0, this loads Child, and no callbacks are passed on before_save :one_last_thing_before_you_go end To prove this, I just typed this into script/console>> class Parent < ActiveRecord::Base >> before_save { puts ''parent'' } >> end=> [#<Proc:0x025b20ec@(irb):3>]>> class Child < Parent >> before_save { puts ''child'' } >> def before_save >> puts ''only child'' >> end >> end=> nil>> Child.new.saveparent child only child Am I just totally missing what you''re saying? I have an article on this topic too: http://weblog.techno-weenie.net/2006/2/21/unitialized-constant-technoweenie. -- Rick Olson http://techno-weenie.net
Rick Olson wrote:> On 3/1/06, Adam Ballai <adam.ballai@integrumtech.com> wrote: > >> Rick Olson wrote: >> >>> Perhaps plugins shouldn''t be defining those methods, and instead use >>> the callback class methods: >>> >>> class Foo < AR::Base >>> before_save :do_this_one_last_thing >>> >>> protected >>> def do_this_one_last_thing >>> end >>> end >>> >>> Otherwise, this could cause issues for someone overwriting a parent''s >>> callback, expecting to override it completely. >>> >>> >> Well thats what the plugins _are_ doing in a mix-in form. >> >> class_eval do >> before_save :something >> end >> >> acts_as_auditable sets before_save :something to -> Parent >> acts_as_ldapable set before_save :something_else to -> Child >> :something to-> Parent becomes ignored instead of calling the parent as >> well... >> >> before_save is a callback for the observer, but it is still a method, so >> you will always override it, unless you call super on it. In one way >> this is proper behavior, but it begs the question, what if we need to do >> more than one different thing before or after a save and they are >> different between types in a single table inheritance scheme. >> >> Either the design meant to make callbacks overrideable via inheritance, >> or missed a tiny detail in implementation. >> >> -- >> -- >> Adam Ballai <adam.ballai@integrumtech.com> >> Integrum Technologies, LLC >> Phone: +1 602 792 1270 x 104 >> Mobile: +1 602 373 3072 >> > > The before_save class method adds the callbacks to an inheritable > array, so they should be passed to the subclasses. Unless, of course, > your subclass is loaded before the before filter: > > class Parent < AR::Base > belongs_to :child # in Rails 1.0, this loads Child, and no callbacks > are passed on > before_save :one_last_thing_before_you_go > end > > To prove this, I just typed this into script/console > > >>> class Parent < ActiveRecord::Base >>> before_save { puts ''parent'' } >>> end >>> > => [#<Proc:0x025b20ec@(irb):3>] > >>> class Child < Parent >>> before_save { puts ''child'' } >>> def before_save >>> puts ''only child'' >>> end >>> end >>> > => nil > >>> Child.new.save >>> > parent > child > only child > > Am I just totally missing what you''re saying? >I think you got it, but I believe what the problem is the test case. Does ruby load the two classes before performing mixins with plugins? Theoretically the write_inheritable_array should append both methods in the child. Parent is loaded, loads plugin, processes callback (do_eval generate after_save) Child is loaded, loads plugin, processes callback (do_eval generate after_save) For some instance where Alien has_many Child and Alien.save will call Parent & Child before_save, but only call the Child.after_save There in lies a problem I think is a callback issue not calling its #super if exists. The patch I binded with the ticket resolves the issue in the application, but nailing the exact test case is tough. Theres no reason the after_save of the parent should not be called. I checked to see if it was STI related by sticking the parent actors into the child and running tests, which accounted for proper behavior. Hopefully we can find some rest in this issue somewhere. -- -- Adam Ballai <adam.ballai@integrumtech.com> Integrum Technologies, LLC Phone: +1 602 792 1270 x 104 Mobile: +1 602 373 3072 _______________________________________________ Rails-core mailing list Rails-core@lists.rubyonrails.org http://lists.rubyonrails.org/mailman/listinfo/rails-core