I was trying to select objects uniq by one attribute, using @videos.uniq{|p| p.author}
time = Time.new(2014, 12) start_time = time.beginning_of_month end_time = time.end_of_month videos = Video.where("created_at > ? AND created_at < ?", start_time, end_time).where("likes > ?", 15) selected_videos = videos.uniq{|p| p.author} puts videos.count, videos.class, selected_videos.count #=> 23, Video::ActiveRecord_Relation, 23 videos_first = videos.first(23) selected_videos = videos_first.uniq{|p| p.author} puts videos_first.count, videos_first.class, selected_videos.count #=> 23, array, 10
.uniq
is not for ActiveRecord_Relation
. And the problem is that the query returns a Video::ActiveRecord_Relation
, but I need array
.
Certainly, this could be achieved by using to_a
, but is this elegant?
.uniq
for activerecord:relation
?The Relation Class. Having queries return an ActiveRecord::Relation object allows us to chain queries together and this Relation class is at the heart of the new query syntax. Let's take a look at this class by searching through the ActiveRecord source code for a file called relation.
Active Record is the M in MVC - the model - which is the layer of the system responsible for representing business data and logic. Active Record facilitates the creation and use of business objects whose data requires persistent storage to a database.
In Rails, pluck is a shortcut to select one or more attributes without loading the corresponding records just to filter out the selected attributes. It returns an Array of attribute values.
If you need to access to the query result, just use #to_a
on ActiveRecord::Relation instance.
At rails guides you can find on notable changes at Rails 4.0: "Model.all now returns an ActiveRecord::Relation, rather than an array of records. Use Relation#to_a if you really want an array. In some specific cases, this may cause breakage when upgrading." That is valid for other relation methods like :where.
selected_videos = videos.to_a.uniq{|p| p.author}
.uniq
does not make much sense when it is applied across the full active-record record.
Given that at least one or more of the three attributes - id
, created_at
, and updated_at
- are different for every row, applying videos.uniq{|p| p.author}
where videos
is a ActiveRecord::Relation
including all fields, will return all the rows in the ActiveRecord::Relation
.
When the ActiveRecord::Relation
object has a subset of values, uniq
will be able to figure out the distinct values from them.
Eg: videos.select(:author).uniq.count
will give 10 in your example.
The difference between ActiveRecord::Relation#uniq
and Array#uniq
is that the Array version accepts a block and uses the return value of a block for comparison. The ActiveRecord::Relation version of uniq simply ignores the block.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With