Search code examples
ruby-on-railsruby-on-rails-4

Rails: How to combine multiple ActiveRecord associations to a single collection


I have something like the following:

class Group < ActiveRecord::Base
  has_many :group_projects, dependent: :destroy
  has_many :projects, through: :group_projects
end

class Projects < ActiveRecord::Base
  has_many :group_projects, dependent: :destroy
  has_many :groups, through: :group_projects

  has_many :time_entries
end

class TimeEntry < ActiveRecord::Base
  belongs_to :project
end

So, project.time_entries returns an ActiveRecord::Associations::CollectionProxy of time_entries belonging to that project.

What I want is a list of all time_entries associated to all projects associated with a particular group as a single collection without having to do something like:

TimeEntry.where(["project_id IN (?)", @group.projects.map{|p| p.id } ])

PS: Using Rails 4.0.0 | ruby 2.0.0


Solution

  • Per the edge docs on subset conditions, you can pass an array to the conditions hash of a where() query. This will return an ActiveRecord::Relation, rather than an array of objects:

    TimeEntry.where(project_id: @group.projects(&:id))
    

    Note the use of the mapping shorthand (the part with the ampersand). It's an alternative and (perhaps) more readable method for returning an array of a single attribute on multiple objects:

    @group.projects.map{|p| p.id} == @group.projects(&:id)