Mitchie Mitchie - 5 months ago 14
Ruby Question

Active Record Relation for Assigned and Created

I currently have a working Active Record association but I was wondering if there was a more efficient way of doing something like this. Basically I have a model called Task. A task has one creator and can be assigned to many people. The user model is a Devise Model called User. This is my current setup but I don't like the query I need to use to fetch all Tasks for a user whether they created them or were assigned to them. Here are my models. My current setup is also terrible with pagination. Any suggestions?

class Task < ActiveRecord::Base
has_and_belongs_to_many :users
belongs_to :creator, foreign_key: 'creator_id', class_name: 'User'
end

class User < ActiveRecord::Base
has_and_belongs_to_many :assigned_tasks, class_name: 'Task'
has_many :created_tasks, foreign_key: 'creator_id', class_name: 'Task'

def tasks
(assigned_tasks.includes(project: [:client]) + created_tasks.includes(project: [:client])).uniq
end
end


So basicslly a Task has to have:


  • One creator (User)

  • Many Users assigned to it



Solution

def tasks
Task.joins('LEFT JOIN tasks_users ON tasks_users.task_id = tasks.id').where('tasks_users.user_id = :user_id OR tasks.creator_id = :user_id', { user_id: id }).includes(project: [:client])
end

Answer

A quick way to do this is:

class User
  def associated_tasks
    Task.joins(:user).joins("LEFT JOIN user_tasks ON user_tasks.task_id = tasks.id").where("users.id = :user_id OR user_tasks.user_id = :user_id", { user_id: id }).includes(project: [:client])
  end
end

Note that we're LEFT JOINing the join table between tasks and users, I called that user_tasks, you should be able to substitute for others.

There are other ways of doing this; I'd update the answer to include these, when I have some time.