ActiveRecord - Instantiation Magic
Have you ever tried to provide default settings for an ActiveRecord model, only to find out it doesn’t work all of the time?
class AModel < ActiveRecord::Base
attr_accessor :default
def initialize
@default='value'
end
end
AModel.new.default # => 'value'
record = AModel.find_by_id( 0 )
record.default # => nil
This is because ActiveRecord doesn’t call the constructor for your model! If you explicitly say AModel.new you are calling your constructor. If you leave it up to ActiveRecord’s finder methods to create an instance of your model it will instead use the allocate method.
What is this allocate method? It’s a class method on Class itself which allocates space for a new object of a given class’s class. Unencrypted, this means that he creates an instance of your class, but doesn’t initialize it! Why is this helpful? Well it can be alot quicker to create a barebones instance instead of calling the constructor on every returned result.
It also seems odd that you would want to set default value(s) on records that you are returning from your database. There are solutions around this problem. Essentially you’d need to override the allocate method on your model’s class.
class AModel < ActiveRecord::Base
attr_accessor :default
def self.allocate
instance = super
instance.instance_variable_set '@default', 'value'
end
end
The question is still left, how should you provide default values for your model instances (records)? Here’s a few tips on the guidlines to follow:
- If the default values are for new records then leave them in your initialize method, since all new records will be created with a call to
YourModel.new - If the default values are for all records, then use your discretion. You can override the allocate method with ease and elegance. Sometimes you need to do this. This can be useful when you need to provide metadata for each record where the information is not stored in the database.
- Make sure you’re not just adding a bunch of data for nothing. This may be a sign of a bad code smell. Does the information you’re giving each record actually belong to the record? Is the data describing your record or acting as a helper to some other object? If it gets more use from another object it may be a sign that the data itself may need to be extracted into the class of the object that is continuously referring to the data.
- Use common sense. If you hardly ever need to access the default data, then why do you need it on every record? It’s going to add more memory overhead and potential slowdowns depending on the number of records you’re dealing with on a regular basis.
For more information on this consult the base.rb file in the activerecord svn source, and look for the private method instantiate. Also, feel free to post!
This article posting was written while Rails 1.0 was the latest stable release.
About this entry
You’re currently reading “ActiveRecord - Instantiation Magic,” an entry on Michigan User Ruby Group
- Published:
- January 18th 04:35 PM
- Updated:
- October 22nd 10:00 PM
- Sections:
- Articles
0 comments
Jump to comment form | comments rss [?]