Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rails select in scope

In my model User, I have scope set up:

scope :count_likes, lambda { 
     select("(SELECT count(*) from another_model) AS count") 
}

If I want to get all attributes of my User + count_likes, I have to do:

Model.count_likes.select("users.*")

because calling select() will the default "*"

I use count_likes scope a lot of my application and my issue is that I have to append select("users.*") everywhere.

I know about the default scope, however, I don't think doing select("users.*") in default scope if a good idea.

Is there a DRY / better way of doing this?

Thanks

like image 579
0xSina Avatar asked Nov 14 '13 08:11

0xSina


1 Answers

This isn't really another answer. I wanted to leave a comment about the joins, but comments cannot run long and I wanted to provide code examples.

What you need is to sometimes get all the fields and counts of a related table, and other times get the counts without the users.* fields, (and maybe sometimes just the user.* fields without the counts). So, you are going to have to tell the code which one you want. I think what you are looking for is an except type of thing, where by default you get the user.* fields and the counts, but when you only want the counts, to specify turning off the select('user.*'). I don't think there is such a solution, except maybe using the default scope. I suggest having one scope for just the counts, and one scope for users fields and the counts.

Here is what I would do:

class Users
  has_many :likes

  def self.with_count_likes
    joins(:likes)
      .select('users.*, count(likes.id) as count')
      .group('users.id')
  end

  def self.count_likes
    joins(:likes)
      .select('users.id, users.username, count(likes.id) as count')
      .group('users.id')
  end
...

Call with_count_likes (or chain it into a query) when you want all the users fields and the likes counts. Call count_likes when you want just the counts and a few identifying fields.

I'm assuming here that whenever you want the counts, you want some users fields to identify what/(who) the counts are for.

Note that some databases (like Oracle) may require grouping by 'users.*'. This is the standard in SQL, but some databases like mySQL only use the primary key.

like image 198
Marlin Pierce Avatar answered Oct 03 '22 00:10

Marlin Pierce