Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rails: correct way of turning activerecord relation to array?

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?

  1. What's the correct way of handling this ?
  2. Is it possible to use .uniq for activerecord:relation?
like image 653
cqcn1991 Avatar asked Jan 06 '15 03:01

cqcn1991


People also ask

What is 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.

What is ActiveRecord in Ruby on Rails?

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.

What does pluck do in Rails?

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.


2 Answers

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} 
like image 104
Alejandro Babio Avatar answered Oct 11 '22 11:10

Alejandro Babio


.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.

like image 33
Prakash Murthy Avatar answered Oct 11 '22 11:10

Prakash Murthy