Vadim Galygin
Vadim Galygin

Reputation: 53

Rails has_many :through complex query

I have these 3 models with has_many :through relation:

class Package < ApplicationRecord
  belongs_to :user
  belongs_to :shipment
end

class User < ApplicationRecord
  has_many :packages
  has_many :shipments, through: :packages
end

class Shipment < ApplicationRecord
  has_many :packages
  has_many :users, through: :packages
end

Given some shipment @shipment, I want to get all users of that shipment, grouped by user_id, and then for each user get packages they have got in this particular @shipment. By using:

@shipment.users.each do |user|
  user.packages
end

I am getting list of all user's packages, but I need to get only packages that are in @shipment. How can I query that?

Upvotes: 0

Views: 301

Answers (2)

Jakub Kosiński
Jakub Kosiński

Reputation: 907

It looks like you can start from your @shipment.packages and then group them by the user_id like so:

@shipment.packages.group_by(:user_id)

As a result you'll get a hash indexed by the user_id where values are the list of shipment's packages with a given user_id.

E.g. assume you have the following packages:

+----------------------------+
| id | user_id | shipment_id |
|  1 |       1 |           1 |
|  2 |       1 |           2 |
|  3 |       2 |           3 |
|  4 |       2 |           1 |
|  5 |       3 |           1 |
|  6 |       2 |           1 |
+----------------------------+

Then you'll get something like this:

@shipment = Shipment.find(1)
@shipment.packages.group_by(&:user_id) #=> {1 => [<Package id=1>], 2 => [<Package id=4>, <Package id=6>], 3 => [<Package id=5>]}

Upvotes: 0

Matt D
Matt D

Reputation: 146

If you wish to keep the same form as you currently do. Try something like:

@shipment.users.group(:email).each do |user|
  user.packages(where: @shipment)
end

Upvotes: 0

Related Questions