has_many :through within same model - ruby-on-rails

I have User model in my database. It has role. role can be either patient or doctor. I want to maintain doctor_patient table.
doctor_patient.rb
belongs_to :doctor, class_name: 'User'
belongs_to :patient, class_name: 'User'
a patient can belong to many doctors and a docor can have many patients. I am familier to regular or normal has_many through association but facing issues related to this scenarios where I have role in user model.
user.rb
user
has_many :doctor_patients
has_many :patients, :through => :doctor_patients, :class_name=> "User"
patient
has_many :doctor_patients
has_many :doctors, :through=> :doctor_patients, :class_name=> "User"

In ActiveRecord the assocation metadata (the reflection) is strored in a class attribute as a hash and the name is used as the key. So when you define multiple assocations with the same name you're just overwriting your previous assocation.
The solution is to use unique names for each assocation:
class User < ApplicationController
has_many :doctor_patients_as_doctor,
foreign_key: :doctor_id,
class_name: 'DoctorPatient'
has_many :patients,
through: :doctor_patients_as_doctor
has_many :doctor_patients_as_patient,
foreign_key: :patient_id,
class_name: 'DoctorPatient'
has_many :doctors,
through: :doctor_patients_as_patient
end
Also make sure you pluralize the table correctly and name it doctor_patients.

Related

Is has_many still necessary when has_many through exists?

I have what I feel like is a super simple question, but I can't find an answer anywhere!
Question:
If I previously had a has_many relationship like this: has_many :wikis, do I keep this relationship if later on I create a has_many through relationship like the following?
has_many :collaborators
has_many :wikis, through: :collaborators
This is all in my User model.
Background:
In my rails app, I have a User model and a Wiki model. I just gave users the ability to collaborate on private wikis so I migrated a Collaborator model and then came the step to create the has_many through relationships. I wasn't sure if I still needed has_many :wikis after putting has_many :wikis, through: :collaborators.
The reason I am confused is because Users should still be able to create wikis without collaborators and I'm not sure how the has_many through relationship works under the hood.
Originally I had only User and Wiki with a one-to-many relationship.
# User model
class User < ApplicationRecord
...
has_many :wikis # should I delete this?
has_many :collaborators
has_many :wikis, through: :collaborators
...
end
# Collaborator model
class Collaborator < ApplicationRecord
belongs_to :user
belongs_to :wiki
end
# Wiki model
class Wiki < ApplicationRecord
belongs_to :user
has_many :collaborators, dependent: :destroy
has_many :users, through: :collaborators
...
end
Is has_many still necessary when has_many through exists?
has_many not necessary when presence has_many through like your model
has_many :wikis # should I delete this?
has_many :collaborators
has_many :wikis, through: :collaborators
should I delete this?
Yes, you can delete this one, you don't need this as the same belongs_to
From The has_many Association
A has_many association indicates a one-to-many connection with another model. You'll often find this association on the "other side" of a belongs_to association. This association indicates that each instance of the model has zero or more instances of another model. For example, in an application containing authors and books, the author model could be declared like this:
From The has_many :through Association:
A has_many :through association is often used to set up a many-to-many connection with another model. This association indicates that the declaring model can be matched with zero or more instances of another model by proceeding through a third model. For example, consider a medical practice where patients make appointments to see physicians. The relevant association declarations could look like this:
class Physician < ApplicationRecord
has_many :appointments
has_many :patients, through: :appointments
end
class Appointment < ApplicationRecord
belongs_to :physician
belongs_to :patient
end
class Patient < ApplicationRecord
has_many :appointments
has_many :physicians, through: :appointments
end
You can work with only has_many association without has_many :through, but this is one-to-many, this not many-to-many
The has_many Association (without has_many :through) is one-to-many connection with another model
The has_many :through Association is up a many-to-many connection with another model
Update
Look, one physician may have many patients, on the other hand, one patient may have many physicians if you use has_many association without through for patient then this called one-to-many association, that means one physician has many patients, on the other hand, one patient belongs to one physician, and now association looks like this
class Physician < ApplicationRecord
has_many :patients
end
class Patient < ApplicationRecord
belongs_to :physician
end
Update 2
The has_many through the standard format your models after edited
# User model
class User < ApplicationRecord
...
has_many :collaborators
has_many :wikis, through: :collaborators
...
end
# Collaborator model
class Collaborator < ApplicationRecord
belongs_to :user
belongs_to :wiki
end
# Wiki model
class Wiki < ApplicationRecord
has_many :collaborators, dependent: :destroy
has_many :users, through: :collaborators
...
end

Making two model from one model

I am building doctor-appointment site. I have User model and I want to divide it into two parts: physician and patient. I have tried:
class User < ActiveRecord::Base
end
class Appointment < ActiveRecord::Base
belongs_to :physician, class_name: "User"
belongs_to :patient, class_name: "User"
end
class Physician < User
has_many :appointments
has_many :patients, through: :appointments, source: "User"
end
class Patient < User
has_many :appointments
has_many :physicians, through: :appointments, source: "User"
end
PROBLEM: how to get physician_id and patient_id column in appointsments table?
I've chosen this way, because when Physician and Patient models are separated, the registration will be problem (I think so...).
I think you're on the right path and only need to run a migration to add references to physician and patient on appointments table.
Although, you wouldn't need to add the source attribute to either the patients or physician has_many through anymore as those would be inferred by Rails!
I think I also prefer this approach of having the Physician and the Patient model, although not for registration purposes, but for single responsibility!
Let me know if that works
add_reference :appointments, :patient, foreign_key: true
add_reference :appointments, :physician, :foreign_key: true
These two migrations should add foreign keys to your table. Check the docs to make sure my syntax is absolutely correct, though.
In addition to the changes dpalazzari suggested I believe you will want to make the following changes:
class Appointment < ActiveRecord::Base
belongs_to :physician, class_name: "Physician", inverse_of: :appointments
belongs_to :patient, class_name: "Patient", inverse_of: :appointments
end
class Physician < User
has_many :appointments, foreign_key: :physician_id, inverse_of: :physician
has_many :patients, through: :appointments, source: "User"
end
class Patient < User
has_many :appointments, foreign_key: :patient_id, inverse_of: :patient
has_many :physicians, through: :appointments, source: "User"
end

Rails has many through with same model

I have one user model and one viewed_contractor model. I am treating user model as customer and contractor. customer can view many contractors by visiting their respective profile.Contractor can be viewed by many customers. I have customer_id and contractor_id in my viewed_contractor. I want to handle this relation as has_many through. Is it possible thorough has_many through?
It is possible. First, you'd need to specify the class_name option for the belongs_to associations in your ViewedContractor model so that they both refer to your User class. Then you could specify the has_many through: relations in your User model.
Something like this should work:
# viewed_contractor.rb
class ViewedContractor < ActiveRecord::Base
belongs_to :contractor, class_name: 'User', foreign_key: :contractor_id
belongs_to :customer, class_name: 'User', foreign_key: :customer_id
end
# user.rb
class User < ActiveRecord::Base
has_many :viewed_contractors_as_contractor, class_name: 'ViewedContractor', foreign_key: :contractor_id
has_many :viewed_contractors_as_customer, class_name: 'ViewedContractor', foreign_key: :customer_id
has_many :visited_contractors, through: :viewed_contractors_as_customer, source: :contractor
has_many :visited_customers, through: :viewed_contractors_as_contractor, source: :customer
end

Ruby ORM polymorphic relationships, Active Record

So I am working with the Ruby ORM and trying to understand many-to-many syntax and polymorphism.
Here are my Active Record relationships so far.
class Association < ActiveRecord::Base
belongs_to :user
belongs_to :friend, class_name: "User"
end
and
class User < ActiveRecord::Base
has_many :associations
has_many :friends, through: :associations
end
I can't seem to get a list of friends per user when those friends are associated with more than one user. In other words some users have friends and these friends may have more than one user association too.
First off, these are not polymorphic associations. One uses polymorphic associations when a model could belong to many models, like a Comment model. A user can comment on a post, on a picture, on a project, so the Comment model could belong to any of these, so there we use Polymorphic associations. Read here to know more about it.
Well, the thing that you are asking is about Inverse Friends, and here is how you can implement it.
class User < ActiveRecord::Base
has_many :associations
has_many :friends, through: :associations
has_many :inverse_associations, class_name: "Association", foreign_key: :friend_id
has_many :inverse_friends, through: :inverse_associations, source: :user
end
class Assocation < ActiveRecord::Base
belongs_to :user
belogns_to :friend, class_name: 'User'
belongs_to :inverse_friend, class_name: 'User', foreign_key: :friend_id
end

A model that belongs_to two models or a polymorphic association?

I have three models
User
Product
Order
A user who submits products and other users can order that product.
Now I want to implement another model payment, where I as an admin pay the user.
Question
I am confused about what kind of association should i create between user, order and payment?
This is what I currently have :
in app/models/user.rb
class User < ActiveRecord::Base
has_many :products_selling, class_name: 'Product'
has_many :orders_received, class_name: 'Order', through: :products_selling, source: :orders
has_many :orders_made, class_name: 'Order'
has_many :products_ordering, class_name: 'Product', through: :orders_made, source: :product
has_one :payment, class_name: 'Payment', through: :orders_received
and in app/models/order.rb
class Order < ActiveRecord::Base
belongs_to :product
belongs_to :buyer, class_name: 'User', foreign_key: :user_id
has_one :seller, class_name: 'User', through: :product
has_one :payment, through: :seller
and in app/models/payment.rb
class Payment < ActiveRecord::Base
belongs_to :user
belongs_to :order
I am not sure what association should be used, I have been reading and there are examples using polymorphic: :true but they were all with has_many, where as in my case one order corresponds to one payment.
Associations
Polymorphic associations basically allow you to use a single table to manage multiple associations:
So if you wanted to link multiple tables to a single table, it will essentially create a pseudo object, which can be associated with different data types. We typically use polymorphic associations with tables which can be used by multiple models, examples including images, errors, posts etc:
In regards to relating polymorphic associations to has_many / has_one, I'm not entirely sure (I can research if you want)
--
Fix
In your case, I would do this:
#app/models/user.rb
class User < ActiveRecord::Base
has_many :orders
has_many :purchases, class_name: 'Order', foreign_key: "buyer_id"
has_many :products
has_many :bought, class_name: 'Product', through: :purchases
end
#app/models/order.rb
class Order < ActiveRecord::Base
belongs_to :user
belongs_to :product
has_one :payment
end
#app/models/payment.rb
Class Payment < ActiveRecord::Base
#fields - id | user_id | order_id | created_at | updated_at
belongs_to :order #-> user pays for order
belongs_to :user #-> user making the payment
end
This will allow you to create payments for each order - which is really what payments are for, right? (You pay for the order, not the product)

Resources