简体   繁体   中英

Rails select in scope with virtual attribute returns an empty ActiveRecord Relation

In a Rails 4.1.2 app with MySQL I'm doing the following:

scope :popular, -> {
  select("images.*, SUM(likes_count + comments_count + reposts_count) as score").
  where("DATE(created_at) > DATE(?)", 4.weeks.ago).
  order('score DESC')
}

to get a recent set of "popular" images. The problem is that if there are no images that match this query, I get an ActiveRecord::Relation with all nil values, eg..

#<ActiveRecord::Relation [#<Image id: nil, user_id: nil, image_uid: nil, image_name: nil>]>

This is causing problems as the collection is not empty. How would I get that scope to return 'nil' if no results, or just reject if the object is empty or something?

UPDATE

Image.popular.select {|i| i.id.present? }

kinda solves the problem, but to me this seems more like a workaround than a solution...

You could make sure you're not returning anything with a nil value for id . Perhaps something like:

scope :popular, -> {
  select("images.*, SUM(likes_count + comments_count + reposts_count) as score").
  where("DATE(created_at) > DATE(?) AND id IS NOT NULL", 4.weeks.ago).
  order('score DESC')
}

EDIT

An alternative approach would be to simplify your query by caching the score attribute on the model. Generate a migration and add your attribute to your model. Then, use a before_save callback:

before_save :cache_score

def cache_score
  self.score = likes_count + comments_count + reposts_count
end

Then you could make your query simpler:

scope :popular, -> { where("created_at > ?", 4.weeks.ago).order('score DESC') }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM