RobotEyes
RobotEyes

Reputation: 5250

How to get all has_many associations from an active record collection

I have two models with has_many through associations; Taskflows and Datasets. They has a join table called DatasetAssignments.

I get all Taskflows using:

@taskflows = Taskflows.all

I know it's possible to get associations from a single ActiveRecord object, eg:

@taskflow.datasets

but is it possible to get all associated Datasets from the @taskflows ActiveRecord collection? Such as @taskflows.datasets

Any help would be much appreciated.

Models:

class Dataset < ActiveRecord::Base
  has_many :dataset_assignments
  has_many :taskflows, :through => :dataset_assignments
end

class Taskflow < ActiveRecord::Base
  has_many :dataset_assignments
  has_many :datasets, :through => :dataset_assignments
end

class DatasetAssignment < ActiveRecord::Base
  belongs_to :dataset
  belongs_to :taskflow
end

Upvotes: 5

Views: 9249

Answers (2)

Nic Nilov
Nic Nilov

Reputation: 5156

Given that @taskflows is an ActiveRecord::Relation, you can do this:

@datasets = Dataset.joins(:dataset_assignments).
    where(dataset_assignments: {taskflow: @taskflows.joins(:datasets) })

or, in the other direction:

@taskflows = Taskflow.joins(:dataset_assignments).
    where(dataset_assignments: {dataset: @datasets.joins(:taskflows) })

joins generates INNER JOINs through many-to-many table and having the receiver being an instance of ActiveRecord::Relation will preserve other conditions.

As @oreoluwa suggested, you can avoid N+1 queries when enumerating by using includes:

@taskflows = Taskflow.joins(...).includes(:datasets)

Upvotes: 7

oreoluwa
oreoluwa

Reputation: 5623

I don't think there is a way to do this, unless you have an outer model, let's call it User, where:

User
  has_many :taskflows
  has_many :datasets, through: :taskflows

or better let your DatasetAssignment belong to the user and fetch all dataset_assignments of a particular User.

Another approach would be to do a @taskflows.map(&:datasets), but it's not effecient.

Or if you only need the datasets to render somewhere and are bothered about effeciency, you should use the AR#includes method like:

@taskflow.includes(:datasets)

Upvotes: 0

Related Questions