Reputation: 4865
I have a Project model. Project model has "all_users" instance method which returns all users of the project.
class Project < ActiveRecord::Base
has_many :memberships
has_many :users, through: :memberships, source: :member, source_type: 'User'
has_many :teams, through: :memberships, source: :member, source_type: 'Team'
scope :all_users, -> (project) {
User.where(%{
(users.id in (select member_id from memberships where project_id = #{project.id} and member_type = 'User')) OR
(users.id in (select user_id from teams_users where team_id IN (select member_id from memberships where project_id = #{project.id} and member_type = 'Team')))
})
}
def all_users
Project.all_users(self).order(:name)
end
end
A user has many projects.
I want to make an instance method in User model to return all users of instance's all projects. Such as:
class User < ActiveRecord::Base
has_many :memberships, as: :member, dependent: :destroy
has_many :projects, through: :memberships
def colleagues
colleagues_of_user = []
projects.each do |project|
project.all_users.each do |user|
colleagues_of_user << user
end
end
teams.each do |team|
team.projects.each do |project|
project.all_users.each do |user|
colleagues_of_user << user
end
end
end
colleagues_of_user.uniq
end
end
The problem is; i want to concatenate all "project.all_users" into one object but i can't. I have to turn them into an array (to_a). But i want the results (colleagues_of_user) in one object ("ActiveRecord::Relation").
UPDATE: Another point that should be noted is;
colleagues_of_user could be:
1. Any user that is member of any projects of the current user.
2. Any user that is member of current user's teams' projects.
I have updated "colleagues" method regarding these notes. How to get all results into one ActiveRecord::Relation object? (Not an array)
Upvotes: 0
Views: 125
Reputation: 6603
Since you want colleagues_of_user to be ActiveRecord::Relation rather than an Array, I think you could do it like this:
def colleagues
colleague_ids = projects_colleague_ids + teams_projects_colleague_ids
colleagues_of_user = User.where(id: colleague_ids.flatten.uniq )
end
private
def projects_colleague_ids(projects = nil)
projects ||= self.projects
projects.includes(:users).collect{ |project| project.all_users.pluck(:id) }.flatten.uniq
end
def teams_projects_colleague_ids
teams.includes(projects: :users).collect do |team|
projects_colleague_ids( team.projects )
end.flatten.uniq
end
Upvotes: 1
Reputation: 854
You can try this with eager loading also.
Project.includes(users).map(&:all_users)
Thanks
Upvotes: 0
Reputation: 1318
I think something like this should work:
def colleagues
projects.map(&:all_users)
end
Upvotes: 0