Skiapex
Skiapex

Reputation: 153

Using has_and_belongs_to_many to get list of associated objects rails

I have two models, Clinician and Patient. A clinician has_many: patients and a patient belongs_to :clinician. A third model, SharedPatient is meant to store additional assosiactions between patients and clinicians as a patient can be shared by many other clinicians besides the one it belongs_to. This is done using a has_and_belongs_to_many relationship.

See models:

class Clinician < ActiveRecord::Base
 has_many :patients
 has_and_belongs_to_many :shared_patients, join_table: 'shared_patients'
end

class Patient < ActiveRecord::Base
 belongs_to :clinician
 has_and_belongs_to_many :shared_clinicians, join_table: 'shared_patients'
end

class SharedPatient < ActiveRecord::Base
 belongs_to :clinician
 belongs_to :patient
end

This is how my models are set out in the db:

Clinician:
 first_name: string
 last_name: string
 user_id: integer

Patient:
 clinician_id: integer
 first_name: string
 last_name: string
 user_id: integer

SharedPatient:
 clinician_id: integer
 patient_id: integer

Using these I would like to show the list of clinicians that a patient is shared with.

This is what I have in my controller now:

@patient = Patient.find_by(user_id: current_user.patient.id)
@clinicianslist = @patient.shared_clinicians

It am trying to show these in a view using:

<% @clinicianslist.each do |list| %>
 <p><%= link_to Clinician.find_by(id: list).full_name, clinician_path(list) %></p>
<% end %>

Using what I have now I am getting an error when trying to load the view:

NameError in Patients#show

uninitialized constant Patient::SharedClinician

I get the same error when running

Patient.find_by(id: 1259).shared_clinicians

in console.

Any advice on solving this error or on structuring the models to get the associations I want would be great. Thanks

Upvotes: 0

Views: 1084

Answers (2)

max
max

Reputation: 102036

I would say that in this case it does not really make that much sense with a join model. It would make sense if it for example was a Appointment object with its own data and logic.

Instead you should create a patients_clinicians join table, and define the relation as:

class Clinician < ActiveRecord::Base
  has_and_belongs_to_many :patients
end

class Patient < ActiveRecord::Base
  has_and_belongs_to_many :clinicians
end

Convention over configuration...

Upvotes: 0

Matt Gibson
Matt Gibson

Reputation: 14949

You don't need the SharedPatient model, so this should be deleted.

The error is because Rails cannot guess the class name from the association name or the table name. Try this:

class Clinician < ActiveRecord::Base
 has_many :patients
 has_and_belongs_to_many :shared_patients, join_table: 'shared_patients', class_name: 'Patient'
end

class Patient < ActiveRecord::Base
 belongs_to :clinician
 has_and_belongs_to_many :shared_clinicians, join_table: 'shared_patients', class_name: 'Clinician'
end

This tells Rails which class to use. Currently, it is guessing SharedClinician, which is wrong.

Upvotes: 3

Related Questions