Hi Suppose we have a User model. For the sake of simplicity, let''s say we need every User instance to have a @foo variable set to value "bar". The normal way to do this is defining an initialize method: class User < ActiveRecord::Base def initialize super @foo = ''bar'' end end This works fine for instances returned by the User.new method (excerpt from the Rails script/console):>> User.new=> #<User:0x40b32548 @attributes={"hashed_password"=>nil}, @new_record=true, @foo="bar"> However, it *does not work* for instances returned by the User.find method:>> User.find 1=> #<User:0x40b2bf54 @attributes={"hashed_password"=>"7522f6e9ec82e5bf71a2374d3acc603d5be7f013", "id"=>"1"}> Notice that the User instance returned by User.find does not have a @foo instance varible set to "bar", although we defined it to be set thus in User#intialize, and we need every User instance to have it set so. First of all, this is somewhat surprising. Obviously a User instance is being constructed somewhere inside User.find. Why doesn''t it get initialize''d the way it normally should? More practically, how do you initialize a model instance? We need to define a function that would be executed immediately and invariably upon instance construction, with that newly constructed instance as the receiver (i.e. the new User instance as ''self''), or at least with a reference to that instance so as to be able to alter it, even if it''s not self (worst case, we can always use instance.instance_eval). Normally we would use User#initialize, which is the regular Ruby initializer, but seeing as it doesn''t work for User.find instances, is there an alternative method/callback we can define? A possible solution would be to wrap User.find: define a method that would call User.find, intercept the User instance returned from it, and alter it in the desired ways. This is suboptimal, since it seems User.find itself is a wrapper for other methods, which might sometimes be called themselves directly (e.g. User.find_by_sql). Under such circumstances, ensuring all instance methods are initialize''d once (and only once) seems more toilsome than it should be. Any advices, thoughts or leads would be appreciated. Regards, Tirkal
On 10/26/05, tirkal <tirkal-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:> Hi > > Suppose we have a User model. For the sake of simplicity, let''s say we > need every User instance to have a @foo variable set to value "bar". > > The normal way to do this is defining an initialize method: > > class User < ActiveRecord::Base > def initialize > super > @foo = ''bar'' > end > end > > This works fine for instances returned by the User.new method (excerpt > from the Rails script/console): > > >> User.new > => #<User:0x40b32548 @attributes={"hashed_password"=>nil}, > @new_record=true, @foo="bar"> > > However, it *does not work* for instances returned by the User.find method: > > >> User.find 1 > => #<User:0x40b2bf54 > @attributes={"hashed_password"=>"7522f6e9ec82e5bf71a2374d3acc603d5be7f013", > "id"=>"1"}> > > Notice that the User instance returned by User.find does not have a > @foo instance varible set to "bar", although we defined it to be set > thus in User#intialize, and we need every User instance to have it set > so. > > First of all, this is somewhat surprising. Obviously a User instance > is being constructed somewhere inside User.find. Why doesn''t it get > initialize''d the way it normally should? > > More practically, how do you initialize a model instance? We need to > define a function that would be executed immediately and invariably > upon instance construction, with that newly constructed instance as > the receiver (i.e. the new User instance as ''self''), or at least with > a reference to that instance so as to be able to alter it, even if > it''s not self (worst case, we can always use instance.instance_eval). > > Normally we would use User#initialize, which is the regular Ruby > initializer, but seeing as it doesn''t work for User.find instances, is > there an alternative method/callback we can define? > > A possible solution would be to wrap User.find: define a method that > would call User.find, intercept the User instance returned from it, > and alter it in the desired ways. This is suboptimal, since it seems > User.find itself is a wrapper for other methods, which might sometimes > be called themselves directly (e.g. User.find_by_sql). Under such > circumstances, ensuring all instance methods are initialize''d once > (and only once) seems more toilsome than it should be. > > Any advices, thoughts or leads would be appreciated. > > Regards,It''s not working because ActiveRecord::Base''s initialize takes an optional attributes hash, and you left that part out. Your best bet is to just use an after_initialize callback. http://rails.rubyonrails.com/classes/ActiveRecord/Callbacks.html -- rick http://techno-weenie.net
Rick Olson said: "It''s not working because ActiveRecord::Base''s initialize takes an optional attributes hash, and you left that part out." I''m really not sure this is the case. If I understand your answer, shouldn''t the addition of "hash={}" to "def initialize" have ammended the problem?: class User < ActiveRecord::Base def initialize(hash={}) super @foo = ''bar'' end end However, even after adding the optional hash argument to User#initialize, I still get the same behavior shown in the console excerpts. In any case, the callbacks you pointed out do seem to address this problem, though I still wonder why the regular User#initialize doesn''t work in this case, as it would be the simplest, ideal solution. Regards, Tirkal On 10/26/05, Rick Olson <technoweenie-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:> On 10/26/05, tirkal <tirkal-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote: > > Hi > > > > Suppose we have a User model. For the sake of simplicity, let''s say we > > need every User instance to have a @foo variable set to value "bar". > > > > The normal way to do this is defining an initialize method: > > > > class User < ActiveRecord::Base > > def initialize > > super > > @foo = ''bar'' > > end > > end > > > > This works fine for instances returned by the User.new method (excerpt > > from the Rails script/console): > > > > >> User.new > > => #<User:0x40b32548 @attributes={"hashed_password"=>nil}, > > @new_record=true, @foo="bar"> > > > > However, it *does not work* for instances returned by the User.find method: > > > > >> User.find 1 > > => #<User:0x40b2bf54 > > @attributes={"hashed_password"=>"7522f6e9ec82e5bf71a2374d3acc603d5be7f013", > > "id"=>"1"}> > > > > Notice that the User instance returned by User.find does not have a > > @foo instance varible set to "bar", although we defined it to be set > > thus in User#intialize, and we need every User instance to have it set > > so. > > > > First of all, this is somewhat surprising. Obviously a User instance > > is being constructed somewhere inside User.find. Why doesn''t it get > > initialize''d the way it normally should? > > > > More practically, how do you initialize a model instance? We need to > > define a function that would be executed immediately and invariably > > upon instance construction, with that newly constructed instance as > > the receiver (i.e. the new User instance as ''self''), or at least with > > a reference to that instance so as to be able to alter it, even if > > it''s not self (worst case, we can always use instance.instance_eval). > > > > Normally we would use User#initialize, which is the regular Ruby > > initializer, but seeing as it doesn''t work for User.find instances, is > > there an alternative method/callback we can define? > > > > A possible solution would be to wrap User.find: define a method that > > would call User.find, intercept the User instance returned from it, > > and alter it in the desired ways. This is suboptimal, since it seems > > User.find itself is a wrapper for other methods, which might sometimes > > be called themselves directly (e.g. User.find_by_sql). Under such > > circumstances, ensuring all instance methods are initialize''d once > > (and only once) seems more toilsome than it should be. > > > > Any advices, thoughts or leads would be appreciated. > > > > Regards, > > > It''s not working because ActiveRecord::Base''s initialize takes an > optional attributes hash, and you left that part out. > > Your best bet is to just use an after_initialize callback. > > http://rails.rubyonrails.com/classes/ActiveRecord/Callbacks.html > -- > rick > http://techno-weenie.net > _______________________________________________ > Rails mailing list > Rails-1W37MKcQCpIf0INCOvqR/iCwEArCW2h5@public.gmane.org > http://lists.rubyonrails.org/mailman/listinfo/rails >
Tirkal, try : class User < ActiveRecord::Base def initialize(*args) super @foo = ''bar'' end end Albert, delamednoll.se tirkal wrote:>Rick Olson said: > >"It''s not working because ActiveRecord::Base''s initialize takes an >optional attributes hash, and you left that part out." > >I''m really not sure this is the case. If I understand your answer, >shouldn''t the addition of "hash={}" to "def initialize" have ammended >the problem?: > >class User < ActiveRecord::Base > def initialize(hash={}) > super > @foo = ''bar'' > end >end > >However, even after adding the optional hash argument to >User#initialize, I still get the same behavior shown in the console >excerpts. > >In any case, the callbacks you pointed out do seem to address this >problem, though I still wonder why the regular User#initialize doesn''t >work in this case, as it would be the simplest, ideal solution. > >Regards, >Tirkal > >On 10/26/05, Rick Olson <technoweenie-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote: > > >>On 10/26/05, tirkal <tirkal-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote: >> >> >>>Hi >>> >>>Suppose we have a User model. For the sake of simplicity, let''s say we >>>need every User instance to have a @foo variable set to value "bar". >>> >>>The normal way to do this is defining an initialize method: >>> >>>class User < ActiveRecord::Base >>> def initialize >>> super >>> @foo = ''bar'' >>> end >>>end >>> >>>This works fine for instances returned by the User.new method (excerpt >>>from the Rails script/console): >>> >>> >>> >>>>>User.new >>>>> >>>>> >>>=> #<User:0x40b32548 @attributes={"hashed_password"=>nil}, >>>@new_record=true, @foo="bar"> >>> >>>However, it *does not work* for instances returned by the User.find method: >>> >>> >>> >>>>>User.find 1 >>>>> >>>>> >>>=> #<User:0x40b2bf54 >>>@attributes={"hashed_password"=>"7522f6e9ec82e5bf71a2374d3acc603d5be7f013", >>>"id"=>"1"}> >>> >>>Notice that the User instance returned by User.find does not have a >>>@foo instance varible set to "bar", although we defined it to be set >>>thus in User#intialize, and we need every User instance to have it set >>>so. >>> >>>First of all, this is somewhat surprising. Obviously a User instance >>>is being constructed somewhere inside User.find. Why doesn''t it get >>>initialize''d the way it normally should? >>> >>>More practically, how do you initialize a model instance? We need to >>>define a function that would be executed immediately and invariably >>>upon instance construction, with that newly constructed instance as >>>the receiver (i.e. the new User instance as ''self''), or at least with >>>a reference to that instance so as to be able to alter it, even if >>>it''s not self (worst case, we can always use instance.instance_eval). >>> >>>Normally we would use User#initialize, which is the regular Ruby >>>initializer, but seeing as it doesn''t work for User.find instances, is >>>there an alternative method/callback we can define? >>> >>>A possible solution would be to wrap User.find: define a method that >>>would call User.find, intercept the User instance returned from it, >>>and alter it in the desired ways. This is suboptimal, since it seems >>>User.find itself is a wrapper for other methods, which might sometimes >>>be called themselves directly (e.g. User.find_by_sql). Under such >>>circumstances, ensuring all instance methods are initialize''d once >>>(and only once) seems more toilsome than it should be. >>> >>>Any advices, thoughts or leads would be appreciated. >>> >>>Regards, >>> >>> >>It''s not working because ActiveRecord::Base''s initialize takes an >>optional attributes hash, and you left that part out. >> >>Your best bet is to just use an after_initialize callback. >> >>http://rails.rubyonrails.com/classes/ActiveRecord/Callbacks.html >>-- >>rick >>http://techno-weenie.net >>_______________________________________________ >>Rails mailing list >>Rails-1W37MKcQCpIf0INCOvqR/iCwEArCW2h5@public.gmane.org >>http://lists.rubyonrails.org/mailman/listinfo/rails >> >> >> >_______________________________________________ >Rails mailing list >Rails-1W37MKcQCpIf0INCOvqR/iCwEArCW2h5@public.gmane.org >http://lists.rubyonrails.org/mailman/listinfo/rails > > > >
Albert Ramstedt said: class User < ActiveRecord::Base def initialize(*args) super @foo = ''bar'' end end Thanks, tried that. Still the same behavior: instances returned from User.new have @foo set correctly, instances returned from User.find - do not. Rails trully diverts here from the Ruby standard practice. I don''t think any form of construction (let alone contruction as standard as the one done by Model.find, which is a very common way to contruct model instances) should bypass the initialization defined by User#initialize. I hope this is changed/clarified, by for now, the best practical path seems to be the callbacks pointed out by Rick Olson. Tirkal On 10/27/05, Albert Ramstedt <soma-7XRkppT4KCs@public.gmane.org> wrote:> Tirkal, try : > > class User < ActiveRecord::Base > def initialize(*args) > super > @foo = ''bar'' > end > end > > Albert, delamednoll.se > > > tirkal wrote: > > >Rick Olson said: > > > >"It''s not working because ActiveRecord::Base''s initialize takes an > >optional attributes hash, and you left that part out." > > > >I''m really not sure this is the case. If I understand your answer, > >shouldn''t the addition of "hash={}" to "def initialize" have ammended > >the problem?: > > > >class User < ActiveRecord::Base > > def initialize(hash={}) > > super > > @foo = ''bar'' > > end > >end > > > >However, even after adding the optional hash argument to > >User#initialize, I still get the same behavior shown in the console > >excerpts. > > > >In any case, the callbacks you pointed out do seem to address this > >problem, though I still wonder why the regular User#initialize doesn''t > >work in this case, as it would be the simplest, ideal solution. > > > >Regards, > >Tirkal > > > >On 10/26/05, Rick Olson <technoweenie-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote: > > > > > >>On 10/26/05, tirkal <tirkal-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote: > >> > >> > >>>Hi > >>> > >>>Suppose we have a User model. For the sake of simplicity, let''s say we > >>>need every User instance to have a @foo variable set to value "bar". > >>> > >>>The normal way to do this is defining an initialize method: > >>> > >>>class User < ActiveRecord::Base > >>> def initialize > >>> super > >>> @foo = ''bar'' > >>> end > >>>end > >>> > >>>This works fine for instances returned by the User.new method (excerpt > >>>from the Rails script/console): > >>> > >>> > >>> > >>>>>User.new > >>>>> > >>>>> > >>>=> #<User:0x40b32548 @attributes={"hashed_password"=>nil}, > >>>@new_record=true, @foo="bar"> > >>> > >>>However, it *does not work* for instances returned by the User.find method: > >>> > >>> > >>> > >>>>>User.find 1 > >>>>> > >>>>> > >>>=> #<User:0x40b2bf54 > >>>@attributes={"hashed_password"=>"7522f6e9ec82e5bf71a2374d3acc603d5be7f013", > >>>"id"=>"1"}> > >>> > >>>Notice that the User instance returned by User.find does not have a > >>>@foo instance varible set to "bar", although we defined it to be set > >>>thus in User#intialize, and we need every User instance to have it set > >>>so. > >>> > >>>First of all, this is somewhat surprising. Obviously a User instance > >>>is being constructed somewhere inside User.find. Why doesn''t it get > >>>initialize''d the way it normally should? > >>> > >>>More practically, how do you initialize a model instance? We need to > >>>define a function that would be executed immediately and invariably > >>>upon instance construction, with that newly constructed instance as > >>>the receiver (i.e. the new User instance as ''self''), or at least with > >>>a reference to that instance so as to be able to alter it, even if > >>>it''s not self (worst case, we can always use instance.instance_eval). > >>> > >>>Normally we would use User#initialize, which is the regular Ruby > >>>initializer, but seeing as it doesn''t work for User.find instances, is > >>>there an alternative method/callback we can define? > >>> > >>>A possible solution would be to wrap User.find: define a method that > >>>would call User.find, intercept the User instance returned from it, > >>>and alter it in the desired ways. This is suboptimal, since it seems > >>>User.find itself is a wrapper for other methods, which might sometimes > >>>be called themselves directly (e.g. User.find_by_sql). Under such > >>>circumstances, ensuring all instance methods are initialize''d once > >>>(and only once) seems more toilsome than it should be. > >>> > >>>Any advices, thoughts or leads would be appreciated. > >>> > >>>Regards, > >>> > >>> > >>It''s not working because ActiveRecord::Base''s initialize takes an > >>optional attributes hash, and you left that part out. > >> > >>Your best bet is to just use an after_initialize callback. > >> > >>http://rails.rubyonrails.com/classes/ActiveRecord/Callbacks.html > >>-- > >>rick > >>http://techno-weenie.net > >>_______________________________________________ > >>Rails mailing list > >>Rails-1W37MKcQCpIf0INCOvqR/iCwEArCW2h5@public.gmane.org > >>http://lists.rubyonrails.org/mailman/listinfo/rails > >> > >> > >> > >_______________________________________________ > >Rails mailing list > >Rails-1W37MKcQCpIf0INCOvqR/iCwEArCW2h5@public.gmane.org > >http://lists.rubyonrails.org/mailman/listinfo/rails > > > > > > > > > _______________________________________________ > Rails mailing list > Rails-1W37MKcQCpIf0INCOvqR/iCwEArCW2h5@public.gmane.org > http://lists.rubyonrails.org/mailman/listinfo/rails >