red-o-alf
red-o-alf

Reputation: 3245

Rails, querying associated records with conditions

I have a User-Group many-to-many association with a join table (group_partecipations) which also has an additional "status" column which takes the following values:

I understand that for DB normalization rules I should extract this column in another table but for now I'll leave it like that.

So.. now, I'm trying to create a query returing, for a given user, all the groups he is owner of and together with that the users for that group with a "pending" state.

Although I found a solution, it felt very complicated and I'm really not sure it's a good way so I would like some advice.

Here's what I came up with:

First I find all groups where user is owner:

groups_where_owner = u.groups.where(group_partecipations: {status: "owner" })

# u.groups would return all groups: 
# either those in which user is owner and those where he is pending or has been accepted

And then for each of his own groups I return an array made of the group itself and the "pending" users:

groups_where_owner.map { |g| 
      [ g, 
        User.includes(:group_partecipations).where
        (:group_partecipations => {:group_id => g.id, status: "pending" })
      ]
}

but as I said, this feels dirty and too much "handmade" and I am trying to understand if I have not missed an important part in ActiveRecord in order to deal with this situation.

Also, when I convert my result into a JSON ojbect it has an additional level of nesting, which I would like to avoid.

So.. is there a better way? Or, what is the correct way?

Thanks in advance for your help.

EDIT: the point of my question is: is there a way to modify my AR query in order to filter out (or avoid including in the first place) all the users who are not "pending" ("owner"s and "accepted"s) so to NOT having to later iterate on the query result to collect those "pending"s" out ?

Upvotes: 1

Views: 364

Answers (1)

dre-hh
dre-hh

Reputation: 8044

This a total acceptable solution.

However it can be improved to make less queries to the db. At the moment you perform a separate query for each owned_group. IO Operations are multiple times slower than cpu Operations. So it is a better strategy to load all the necessary data at once and then process it.

Group.includes(group_participations: :user)
  where(group_participations: {status: "pending" }).
  where(id: user.groups.where(group_participations: {status: "owner" }).ids).
  map { |g| [g, g.users]} 

Upvotes: 1

Related Questions