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 >