Search code examples
ruby-on-railsrubydeviserails-activerecordruby-on-rails-7

Rails 7, return active record association with two separate conditions, one in the parent, one in the child


I have an Applicant model, that has become the location or a chat between a project owner and an applicant to that project.

I track the applicant by using an applicant.user reference in the Applicant table.

I track the project owner by using applicant.project.user, which is a reference in the Project table (a parent of Applicant).

As I say, the Applicant table also has a child of Messages, and Applicant is essentially a chat view between two users.

Users are managed using Devise.

One other field to mention in the Applicant table is a last_message field, that gets updated whenever a user creates a new message for that Applicant record.

class Applicant < ApplicationRecord
  belongs_to :project
  belongs_to :user
  has_many :messages, dependent: :destroy
end
class Project < ApplicationRecord
  belongs_to :user
  has_many :applicants, dependent: :destroy
  has_rich_text :description
end
class User < ApplicationRecord
  has_many :projects, dependent: :destroy
  has_many :applicants, dependent: :destroy
  has_rich_text :about

  devise :database_authenticatable, :registerable, :confirmable, :trackable,
         :recoverable, :rememberable, :validatable
end
class Message < ApplicationRecord
  belongs_to :applicant
end

I want to get a list of any users 'chats' (or Applicants). This is both their projects and their applicants.

I am currently doing this:

project_messages = []

current_user.projects.each do |project|
  project.applicants.each do |applicant|
    project_messages << applicant
  end
end

@chats = Applicant
  .where(id: (current_user.applicants + project_messages)
  .map(&:id))
  .order(last_message: :desc)

Here I get a list of the current_user projects and add each applicant (chat room) into an array. I then add this to the current_user.applicants. Then I merge both together as an Active record association.

This works, but I feel that it is a bad way to do this. Does anybody know a more efficient way of doing this?


Solution

  • You can join applicants and projects tables and check if current user is applicant or project "owner" like this

    applicants =
      Applicant
        .joins(:project)
        .where('applicants.user_id = :id OR projects.user_id = :id', id: current_user.id)
        .order(last_message: :desc)