简体   繁体   中英

Rails Active Record different association results into one object

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)

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

I think something like this should work:

def colleagues
  projects.map(&:all_users)
end

You can try this with eager loading also.

Project.includes(users).map(&:all_users)

Thanks

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM