Rails - has_one :through and has_many :through - ruby-on-rails

I want to design a club system. A club has many users, a user has one club, and a membership to store some info.
Can I use has_one :through and has_many :through to build one-to-many associations?
class Club < ApplicationRecord
has_many :users, through: :memberships
has_many :memberships
end
class Membership < ApplicationRecord
belongs_to :club
belongs_to :user
end
class User < ApplicationRecord
has_one :club, through: :membership
has_one :membership
end
Because in the Rails Guides, it mentions has_one :through to build one-to-one association, and has_many :through to build many-to-many association.
Can I use this way? Thanks.

You can. You have to adjust your models a bit to define your through part before defining another association that goes through it, i.e.
class Club < ApplicationRecord
has_many :memberships
has_many :users, through: :memberships
end
class User < ApplicationRecord
has_one :membership
has_one :club, through: :membership
end

Related

How to differentiate similar has_many :through associations in Rails?

I'll start off with my models:
class Project < ApplicationRecord
has_many :permissions
has_many :wallets, through: :permissions
has_many :follows
has_many :wallets, through: :follows
end
class Permission < ApplicationRecord
belongs_to :project
belongs_to :wallet
end
class Follow < ApplicationRecord
belongs_to :project
belongs_to :wallet
end
class Wallet < ApplicationRecord
has_many :permissions
has_many :projects, through: :permissions
has_many :follows
has_many :projects, through: :follows
end
As you can see, Permission and Follow are both through associations for Projects and Wallets.
They serve different purposes (Permission gives Wallets access to manage Projects while Follow lets Wallets "follow" projects for updates).
So how can I differentiate them? For example, if I do Wallet.find(1).projects, it defaults to using the "Follow" model...though in some scenarios I'd want it to actually use the "Permission" model.
Believe you'd find it will default to the has_many :projects that is defined last.
Need to give the associations different names, which will require something like ...
class Wallet < ApplicationRecord
has_many :permissions
has_many :projects, through: :permissions
has_many :follows
has_many :follow_projects, through: :follows, source: :project
end

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

How to do `has_one: model, through: join_model` in JSONAPI::Resource

What's the preferred way to do has_one :model, through: join_model in a model resource? Usually JSONAPI::Resource expects model_id column on the table/model who owns the association. That does not exist if a join table/model is used.
You can actually just mention the has_many relationship, with no need to mention the through association.
So if you had this model structure:
class Teacher < ActiveRecord::Base
has_many :classrooms
has_many :students, through: :classrooms
end
class Student < ActiveRecord::Base
has_many :classrooms
has_many :teachers, through: :classrooms
end
class Classroom < ActiveRecord::Base
belongs_to :teacher
belongs_to :student
end
In your Teacher resource, all you'd need is has_many :students.
And likewise, in your Student resource, you'd need has_many :teachers.

Ruby on Rails - Association

I have to create relationship between student, courses and enrolment.
One student can enrol in only one course.
A course can be enrolled by many students.
How to acheive this ?
I was able to create has_many_through relationship like this
class
Student < User
has_many :enrollments
has_many :course , through: :enrollments
end
class Course < ActiveRecord::Base
has_many :enrollments
has_many :students, through: :enrollments, class_name: "User"
end
class Enrollment < ActiveRecord::Base
belongs_to :student, class_name: "User"
belongs_to :course
end
But this works only for has_many on both the sides of students and courses.
But I want only one student to enrol in one course like this
class Student < User
has_one :enrollment
has_one :course , through: :enrollment
end
But this does not work. When I do this
Student.first.enrollment.create(course: Course.last)
I get an error like this
NoMethodError: undefined method `enrollment' for #<Student:0x007f7ff8baf4a8>
Thanks to Marek Lipka for suggesting this solution.
Add validation in Enrollment
class Enrollment < ActiveRecord::Base
belongs_to :student, class_name: "User"
belongs_to :course
validates :student , uniqueness: true
end
And use has_many enrollments
class Student < User
has_many :enrollments
has_many :course , through: :enrollments
end

many-to-many: has_many :through and User table relation issue in rails 4

My setup for the models:
class Doctor < ActiveRecord::Base
has_many :appointments
has_many :patients, :through => :appointments
end
class Appointment < ActiveRecord::Base
belongs_to :doctor
belongs_to :patient
end
class Patient < ActiveRecord::Base
has_many :appointments
has_many :physicians, :through => :appointments
end
In my application LogedIn-User IS A either doctor,patient or the Admin i got understand that how Doctor and patient relationship work with appointment,But how to setup the user model and table for that
class User_type < ActiveRecord::Base
belongs_to :doctors, class_name: "USER"
belongs_to :patients, class_name: "USER"
end
I know that I am missing crucial self association here but how can i do that, or any other way to set up these models and tables for that. Thanks in advance.
class User < ActiveRecord::Base
has_one :doctor
has_one :patient
end
class Doctor < ActiveRecord::Base
belongs_to :user
has_many :appointments
has_many :patients, :through => :appointments
end
class Appointment < ActiveRecord::Base
belongs_to :physician
belongs_to :patient
end
class Patient < ActiveRecord::Base
belongs_to :user
has_many :appointments
has_many :physicians, :through => :appointments
end
Hope this will work for you, If you understand many to many relationship properly.
You have typo in here: class User_type < ActiveRecord::Base
belongs-to :doctors, class_name: "USER"
belongs_to :patients, class_name: "USER"
end
it should be belongs_to, you sure thats not your problem?

Resources