views:

242

answers:

1

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?

+1  A: 

Instead of creating an additional method, you could perhaps create a method on the association proxy called 'ids' so that you could do e.g. this:

User.named_scope :recent, ...
User.named_scope :admin, ...
User.recent.admin.ids

And yeah, that sounds like a sensible plugin to me. Shouldn't be too hard to write.

August Lilleaas