Reputation: 2380
I have a rails app. I would like to display user profiles ordered by the number of the common tasks they have with the current user. Every task has one assigner and one executor. The number should include both the executed_tasks and assigned_tasks for the same user. So for example if current_user assigned 5 tasks to User4 and User4 assigned 3 tasks to current_user then this number would be 8.
My main problem is that I don't know how to use the given user as arg for the count. Should I do in the model somehow or when I set the instance variable (@users) in the controller?
task.rb
belongs_to :assigner, class_name: "User"
belongs_to :executor, class_name: "User"
scope :between, -> (assigner_id, executor_id) do
where("(tasks.assigner_id = ? AND tasks.executor_id = ?) OR (tasks.assigner_id = ? AND tasks.executor_id = ?)", assigner_id, executor_id, executor_id, assigner_id)
end
user.rb
has_many :assigned_tasks, class_name: "Task", foreign_key: "assigner_id", dependent: :destroy
has_many :executed_tasks, class_name: "Task", foreign_key: "executor_id", dependent: :destroy
Upvotes: 0
Views: 306
Reputation: 2166
Assuming that you want to execute this with a single SQL query to improve performance, you could do something like:
class User < ActiveRecord::Base
def assigners
Task.where(executor_id: id).select('assigner_id AS user_id')
end
def executors
Task.where(assigner_id: id).select('executor_id AS user_id')
end
def relations_sql
"((#{assigners.to_sql}) UNION ALL (#{executors.to_sql})) AS relations"
end
def ordered_relating_users
User.joins("RIGHT OUTER JOIN #{relations_sql} ON relations.user_id = users.id")
.group(:id)
.order('COUNT(relations.user_id) DESC')
end
end
As the comment requests for taking into account the unrelating users, and limit to 6, it's a little bit trickier, since we use FULL_OUTER_JOIN
.The edited function would be:
def ordered_relating_users
User.joins("FULL OUTER JOIN #{relations_sql} ON relations.user_id = users.id")
.where.not(id: id)
.group(:id)
.order('COUNT(relations.user_id) DESC')
.limit(6)
end
Upvotes: 1