1
votes

Using the has_many :through association example from the RailsGuide, how do you select all patients or physicians without appointments using ActiveRecord?


2.4 The has_many :through Association http://guides.rubyonrails.org/association_basics.html#the-has-many-through-association

class Physician < ActiveRecord::Base
  has_many :appointments
  has_many :patients, through: :appointments
end

class Appointment < ActiveRecord::Base
  belongs_to :physician
  belongs_to :patient
end

class Patient < ActiveRecord::Base
  has_many :appointments
  has_many :physicians, through: :appointments
end

class User < ActiveRecord::Base
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable and :omniauthable
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :trackable, :validatable

    has_many :enrollments
    has_many :courses, through: :enrollments

end

class Enrollment < ActiveRecord::Base
    belongs_to :course
    belongs_to :user

    scope :registered, -> { where("enrolled = ?", true) }
    scope :student, -> (student_id) { where("user_id = ?", student_id) }
end

class Course < ActiveRecord::Base
    before_save :update_slug

    has_many :enrollments
    has_many :users, through: :enrollments

    def update_slug
        self.slug = title.parameterize
    end

    def to_param
        slug
    end

    # scope :available, -> { where.not(id: Enrollment.pluck(:course_id)).uniq }
    scope :available, -> (student_id) { where.not(id: Enrollment.pluck(:course_id)).uniq }
end
2

2 Answers

1
votes

The simplest thing you can do is to first select all the IDs from the join table/model, and then use the list to exclude records from the second query:

Physician.where.not(id: Appointment.pluck(:physician_id).uniq)
Patient.where.not(id: Appointment.pluck(:patient_id).uniq)
1
votes

You could also use pure SQL which i personally prefer:

Physician.where("
  not exists (select 1 from appointments 
  where appointments.physician_id = physician.id)
")

Patient("
  not exists (select 1 from appointments 
  where appointments.patient_id = patient.id)
")

As for "How could I filter the records based on which Patient is signed?", what exactly do you mean?

Appointment.find_by(patient_id: 123).patient
Appointment.find_by(patient_id: 123).physician