In ruby on rails, all has_many :widgets
methods generate both a object.widgets
method and an object.widget_ids
method.
The latter method is very useful because it bypasses the creation of ActiveRecord objects and runs a much faster query. The query speed can be improved by using the :select
option, but ruby still allocates much more memory when generating objects instead of integers.
For example
User has_many :historical_sessions:
>> Benchmark.measure { User.find(4).historical_sessions.map(&:id) }
HistoricalSession Load (131.0ms) SELECT * FROM `historical_sessions` WHERE (`historical_sessions`.user_id = 4)
=> #<Benchmark::Tms:0xbe805c0 @cutime=0.0, @label="", @total=1.996, @stime=0.0150000000000006, @real=2.09599995613098, @utime=1.981, @cstime=0.0>
(2.1 seconds)
>> Benchmark.measure { User.find(4).historical_session_ids }
HistoricalSession Load (34.0ms) SELECT `historical_sessions`.id FROM `historical_sessions` WHERE (`historical_sessions`.user_id = 4)
=> #<Benchmark::Tms:0x11e6cd94 @cutime=0.0, @label="", @total=1.529, @stime=0.032, @real=1.55099987983704, @utime=1.497, @cstime=0.0>
(1.6 seconds)
(The result set is 67353 objects)
Is there a way to have the same behavior occur when using named_scopes?
For example,
User named_scope :recent
User.recent (Exists)
User.recent_ids (Does not exist)
The way I currently get the ids of objects in a named scope result set is: HistoricalSession.recent.map(&:id). This is essentially similar to what is done in the latter example above, and is obviously not efficient. I do not want to build entire HistoricalSession objects when in the end all I need is an array of ids.
An alternate implementation could be a new .find method. For example, HistoricalSession.recent.find_attributes(:id). This method would replace the select statement to only select the specified values and would short circuit ActiveRecord object creation to just return an array.
Any suggestions? Might this be a simple plugin to write?