- Settings:
Page
Normal
Plain layout without fancy styles
Font
Normal
Large fonts
Very large fonts
Colour
Normal
Restful colour scheme
Light text on a dark background

Note: user account creation on this site has been disabled.

Programming, speculative fiction, science, technology
Powered by Drupal, an open source content management system
Scope
Include Children
If you select a term with children (sub-terms), do you want those child terms automatically included in the search? This requires that "Items containing" be "any."
Categories

Everything in the Events vocabulary

"Events" is used for: Convention Post, Page, Story.

People mentioned in the articles

"People" is used for: Page, Convention Post, Story.

Themes mentioned in the article

"Themes" is used for: Page, Convention Post, Story.
Skip to top of page

Ruby uniq method with ActiveRecord

Recently I was surprised to see that Ruby uniq method didn't seem to work on ActiveRecord. Suppose I have a bunch of ActiveRecords and I want to select just the ones that are unique by some field.

For example, I have a table visit (representing a visitor's visit to a website). It's a very simple table consisting of a visitor's browser, operating system, and screen resolution. (No, it's not in a cannonical form, but that's irrelevant for our example.)

browser os resolution
iPhone iOS 320x480
Safari iOS 768x1024
iPhone iOS 320x568
Chrome Android 720x1280
Android Android 455x761
Chrome Win8 1366x768
Chrome Win7 1920x1080
IE WinVista 1600x900

The records in this table are retrieved via a class derived from ActiveRecord:


class Visit < ActiveRecord::Base

end

Any Visit object will have fields browser, os, and resolution.

Suppose we want to retrieve all the records that have a unique os field. That is to say, for every OS represented in the table, I want to get only one record with that OS (doesn't matter which one). I want a collection of such records. I tried to retrieve them the "obvious" way:

unique_os_records = Visit.all.uniq { |visit| visit.os }

To my surprise, it didn't give me only the records with different OS'es. It gave me all the records. The mystery became clear when somebody suggested to me to check what kind of object Visit.all returns. Turns out, it's not an Array, as I was assuming for some reason! It's an ActiveRecord::Relation. And uniq method only works on arrays. Interestingly, calling uniq on ActiveRecord::Relation does not throw "Method missing" error, even though ActiveRecord::Relation documentation does not say it has such a method. Maybe I'm using an older version of ActiveRecord where that method existed?

In any case, the solution is to convert Visit.all to array:

unique_os_records = Visit.all.to_a.uniq { |v| v.os }

Now unique_os_records will contain just one record for each OS.