Finding unique records, ordered by field in association, with PostgreSQL and Rails 3?-Collection of common programming errors
UPDATE: So thanks to @Erwin Brandstetter, I now have this:
def self.unique_users_by_company(company)
users = User.arel_table
cards = Card.arel_table
users_columns = User.column_names.map { |col| users[col.to_sym] }
cards_condition = cards[:company_id].eq(company.id).
and(cards[:user_id].eq(users[:id]))
User.joins(:cards).where(cards_condition).group(users_columns).
order('min(cards.created_at)')
end
… which seems to do exactly what I want. There are two shortcomings that I would still like to have addressed, however:
- The
order()
clause is using straight SQL instead of Arel (couldn’t figure it out). -
Calling
.count
on the query above gives me this error:NoMethodError: undefined method ‘to_sym’ for # from /Users/neezer/.rvm/gems/ruby-1.9.3-p0/gems/activerecord-3.1.1/lib/active_record/relation/calculations.rb:227:in ‘execute_grouped_calculation’
… which I believe is probably related to how I’m mapping out the
users_columns
, so I don’t have to manually type in all of them in thegroup
clause.
How can I fix those two issues?
ORIGINAL QUESTION:
Here’s what I have so far that solves the first part of my question:
def self.unique_users_by_company(company)
users = User.arel_table
cards = Card.arel_table
cards_condition = cards[:company_id].eq(company.id)
.and(cards[:user_id].eq(users[:id]))
User.where(Card.where(cards_condition).exists)
end
This gives me 84 unique records, which is correct.
The problem is that I need those User
records ordered by cards[:created_at]
(whichever is earliest for that particular user). Appending .order(cards[:created_at])
to the scope at the end of the method above does absolutely nothing.
I tried adding in a .joins(:cards)
, but that give returns 587 records, which is incorrect (duplicate User
s). group_by
as I understand it is practically useless here as well, because of how PostgreSQL handles it.
I need my result to be an ActiveRecord::Relation
(so it’s chainable) that returns a list of unique users who have cards that belong to a given company, ordered by the creation date of their first card… with a query that’s written in Ruby and is database-agnostic. How can I do this?
class Company
has_many :cards
end
class Card
belongs_to :user
belongs_to :company
end
class User
has_many :cards
end
Please let me know if you need any other information, or if I wasn’t clear in my question.