ActiveRecord::Base doesn't always use
new
to create objects, so
initialize
might not be called.
I wanted to use a Hash on an
ActiveRecord::Base
subclass to store some calculated values, so I naively did this:
class User < ActiveRecord::Base
def initialize(args = nil)
super
@my_cache = {}
end
end
However I quickly ran into some "
You have a nil object when you didn't expect it!
" issues. Some debugger investigation revealed that the
@my_cache
variable wasn't being set when I called
find_or_create_
if the object already existed in the database.
Digging in the source revealed that the
instantiate
method in active_record/base.rb uses
allocate
to create classes rather than
new
. This means the
initialize
method is being neatly sidestepped when creating objects from the database.
The solution is to use the '
after_initialize
' callback:
class User < ActiveRecord::Base
def after_initialize
@my_cache = {}
end
end
One further note of caution, When passing parameters into a
new
or
create
method the
after_initialize
is called after the parameters have been set. So you can't rely on the initialization being done before overridden accessors are called.
25 comments:
Thanks - this information was just what I needed :)
Thank you Thank you Thank you
Thank you!
Thank you!! One year old post still benefiting Rails users :)
Thanks for this post.
Two things:
1) I had to use 'self.myattribute' instead of '@myattribute' - not sure why (I'm pretty new)
2) Remember to check whether 'myattribute' is null, otherwise you'll overwrite what is in your db when you recall the object.
Thanks - That's just fixed a very long standing bug of mine - I was using "before_create" but it wasn't getting called early enough.. xxx
@SoccerShoutPhil 1) Not sure, I've not done any Rails for a while. 2) I used this method for calculated values that would not be stored in the database.
Thanks a lot!!!!!!
You saved the day (looked 4 hours for the error ..)
Thanks for the great description. This saved me a ton of time.
I've found that I need to use both.
I have an AR object that handles a few different files. I got sick of defining setter methods to handle these files so I created a method to automatically generate the setters using class_eval. Unfortunately, I have to call the method twice. Once in initalize so it works for new objects and once again in after_initalize so it works for updates. In after_initalize I also have to check that the file setter methods haven't been created already so that's additional overhead.
It all works but I worry that the code is much less clear than I originally intended.
Thanks, that really helps. I mean, I actually needed to do what you said not to do, but the code helped :)
thnaks! thats w0rk3d for me, but
DEPRECATION WARNING: Base#after_initialize has been deprecated, please use Base.after_initialize :method instead.
You have saved me a day. Thanks.
Thanks -- exactly what I wanted to do and exactly the problem I ran into.
Excellent. That's just what was confusing me, thanks.
This is nice, but you still might need to overwrite ActiveRecord's initialize function. I think your error is due to the fact that the initializer takes a Hash as an argument, which explains you're "You have a nil object when you didn't expect it!". The proper call to override it would be this if I'm not mistaken:
class User < ActiveRecord::Base
def initialize(args = {})
super
@my_cache = {}
end
end
Then you'll see those error messages go away.
@Unknown Thanks for your comment, I've not looked at the code for a while but the issue I had was that initialize wasn't called at all when active record loaded the object back from the DB.
Seems in Rails 3.2 the syntax has changed:
class User < ActiveRecord::Base
after_initialize do
@my_cache = {}
end
end
worked for me
As "Blog-Name" stated, this is also the case for Rails 3.1
Dịch vụ chuyển phát nhanh ở tphcm ngày ngày càng phát triển góp phần nâng cao dịch vụ mua bán đặc biệt mua bán online. Nên các chuyển phát nhanh tphcm luôn được phát triển nâng cao nhu cầu phục vụ công ty doanh nghiệp. Dịch vụ chuyển phát nhanh của Công ty Proship đã được nhiều tổ chức, doanh nghiệp, cá nhân yêu mến, tin cậy và hợp tác lâu dài. Trong quá trình xây dựng và phát triển, chúng tôi công ty chuyển phát nhanh tại tphcm là hiện thân cho tinh thần trách nhiệm và trung thực, dịch vụ chu đáo và nhanh chóng. Tại thị trường Tphcm, Proship được đánh giá là một trong những Công ty Chuyển phát nhanh làm ăn có hiệu quả, uy tín, có sức phát triển và dành được nhiều cảm mến. Chuyên cung cấp các dịch vụ gửi hàng vào sài gòn .Ngoài dịch vụ nhanh chóng, chu đáo và giá cả hợp lý thì Proship cũng có nhiều chương trình khuyến mãi cho các khách hàng tại Sài Gòn. Nên nếu bạn là cá nhân hay công ty doanh nghiệp đang có nhu cầu sử dụng giá chuyển phát nhanh vào sài gòn hãy liên hệ với chúng tôi công ty Proship. Với những uy tín vốn có của doanh nghiệp, chuyển phát Proship nhận vận chuyển các loại hàng hóa và bưu phẩm theo yêu cầu của khách hàng. Với thời gian 1 ngày duy nhất cho quá trình vận chuyển hàng từ các tỉnh thành trên cả nước và chuyển phát nhanh uy tín tại sài gòn , chúng tôi sẽ nhận hàng của quý khách tại văn phòng hoặc tại nhà riêng, công ty sau đó sẽ kết nối vào Đà Nẵng và phát tận tay người nhận theo địa chỉ ghi trên bưu kiện. Nếu bạn có nhu cầu sử dụng dịch vụ ship hàng Nhật chúng tôi đáp ứng cho bạn với chi phí và giá phải chăn nhất.Hay tham quan bruno xem nhiều mặt hàng thời trang khác.
Bạn đang muốn Mua hàng trên amazon, Mua hàng trên ebay nhưng amazon chưa có ship về hàng về Việt Nam. Bạn hãy đến với chúng tôi nhận ship hàng ebay, ship hàng amazon,ship hàng Mỹ, ship hàng từ Mỹ về Việt Nam, gửi hàng từ mỹ về việt nam, vận chuyển hàng từ mỹ về việt nam
rượu nhung hươu
Post a Comment