Confusing ActiveRecord relationship - Ruby on Rails - ruby-on-rails

I am trying to design the relationships for a doctor and their training programs/specialties. Example below:
A program has one specialty/program (ex. University Neurology Training program specializes in neurology)
A doctor can have multiple programs and thus multiple specialties (ex. Dr. Smith is a neurologist who attended University Neurology Training program, while Dr. Jones is a neurologist and pediatrician who attended University Neurology Traning Program and Big Hospital Pediatrics Program)
It would seem that it could be set up as a has_many :through ... However, this doesn't seem efficient or correct when I try to conceptualize it. I have another largely unrelated model that ties in with the specialty (but not the program), that's why I don't combine the program and specialty. I should be able to access User.programs.all and Program.users.all :
Model User:
has_many programs
has_many specialties, :through => :programs
Model Program:
belongs_to :user
belongs_to :specialty
Model Specialty:
has_many :users, :through => :program
has_many :programs

You can have models something like below.
class Doctor
has_many :specialties, :through => :practices
has_many : enrollments
has_many :programs , :through => : enrollments
end
class Program
has_many : enrollments
has_many :doctors, :through => : enrollments
belongs_to :specialty
end
class Enrollment
belongs_to : doctor
belongs_to :program
end
class Specialty
has_many :practices
has_many :doctors, :through => :practices
has_many :programs
end
class Practice
belongs_to :doctor
belongs_to :specialty
end
Hope it helps.
Update
If a doctor can only have specialty via a program then it can be modeled like this.
class Doctor
has_many :enrollments
has_many :programs, :through => :enrollments
end
class Program
has_many :enrollments
has_many :doctors, :through => :enrollments
belongs_to :specialty
end
class Enrollment
belongs_to :doctor
belongs_to :program
end
class Specialty
has_many :programs
has_many :enrollments , :through => :programs
end
To get all the doctors of a specialty eg neurology.
#neurology.enrollments.collect { |c| c.doctor }.uniq
Or
Doctor.includes(:enrollments).where(:enrollments => {:specialty_id => #neurology.id})
To get all specialties of a doctor you have to do like this.
#doctor.programs.collect { |p| p.specialty }.uniq

Do not link to specialty via programs.
Make it so that specialties and programs are independent.
It seems like you have a good chance of running into a case where doctor has a specialty, but did not attend any meaningful "programs".
You may add as "soft" link from specialties to programs: in model Specialty add "belongs_to :program", with a possibility of program being NULL.

Related

Rails multi level association

New to Ruby, Rails, and OOP in general. I've been through the "Ruby on Rails Tutorial: Learn Web Development with Rails" and about 80% through "Agile Web Development with Rails 4" but I can't visually figure this out. I was hoping someone can help me understand, maybe I'm wording it wrong.
Models: User, Team, Membership, Order, OrderLine
It's a pretty basic setup. (short hand, if you will...)
Team belongs_to :user (owner, not terribly relevant here)
Users has_many :teams through: :memberships
Team has_many :users through: :memberships
OrderLine belongs_to :team
Note an OrderLine is assigned to a team, not a whole Order.
I'm trying to display all OrderLines which are associated with the currently logged in user (current_user). While this doesn't actually work, I feel it's close to producing. It also feels super dirty.
def index
#memberships = current_user.memberships.ids
membership_list = #memberships.join(", ")
#OrderLines = OrderLine.where("team_id IN (?)", membership_list)
end
Cheers!
# Model
class User < ActiveRecord::Base
has_many :owned_team, :class_name => "Team"
has_many :teams
has_many :memberships
has_many :order_lines, through: :memberships
class Team < ActiveRecord::Base
belongs_to :faction
belongs_to :region
belongs_to :owner, :class_name => "User"
has_many :users, through: :memberships
has_many :order_lines
class Membership < ActiveRecord::Base
belongs_to :user
belongs_to :team
has_many :order_lines, through: :team
# Controller
#OrderLines = current_user.order_lines
Some times all you need is a break.

How to fix my model associations

I'm struggling to understand model associations, and how to have them set up correctly. I'm hoping someone here knows how, and that I can kind of explain what I want to accomplish.
I have a user model that looks like this:
has_many :companies
has_many :contacts
belongs_to :company
a user can create a company, and belongs to a company. It can also import contacts from email providers (such as Google). Thus it can have many contacts.
Then we have the company model:
belongs_to :admin, class_name: 'User', foreign_key: 'user_id'
has_many :users
has_many :categories
has_many :contacts
a company belongs to an admin, which is the user that creates it. It can also however have several users that belongs to the company (they get invited by the admin). It also has categories, that the admin can create - which belongs to the company. It can also have contacts, which will be put the content of the categories (the categories are groups for contacts).
Then we have the categories. They are created by the admin (user) for the company.
belongs_to :company
has_many :contacts
The categories store all the contacts.
Then lastly the contacts:
belongs_to :user
belongs_to :company
The contacts belongs to the user (the user that imports them) however they are also a part of the assets to the company (as all the actions the user makes), they don't necessarily need to be a part of a category, however they can - and can also be a part of several categories.
I'm certain there are some flaws, and I want to fix my associations now so I don't end up building a lot of code on the wrong structure.
Hope somebody can help me out, on how to clean up this relatively large app, for a rookie
I'd change a few things:
In the company model, change has_many :contacts to has_many :contacts, through: :categories. It seems like categories only serve to group contacts together. And so therefore:
In the contact model, add belongs_to :category and remove belongs_to :company
Users and contacts do not have to be associated if a user wants to import contacts. I would either remove this association entirely if you don't need it or have a the same has_many :categories and has_many :contacts, through: :categories relationship as the companies. Of course, remove belongs_to :user in the contacts.
You might look into polymorphism. I'm doing something like this although I stripped out and and renamed a few things to more closely match your question. This is untested but might help illustrate a different approach
class User < ActiveRecord::Base
has_many :business_users
has_many :businesses, :through => business_users
has_many :contacts, :through => :contact_users
...
end
class Contact < ActiveRecord::Base
belongs_to :user
belongs_to :company
has_many :categorizations, :as => :categorizeable
has_many :categories, -> { order(created_at: :desc) }, :through => :categorizations
...
end
class Company < ActiveRecord::Base
belongs_to :admin, :class_name => :User, :foreign_key => "user_id"
has_many :company_users
has_many :users, :through => :company_users
has_many :categorizations, :as => :categorizeable
has_many :categories, -> { order(created_at: :desc) }, :through => :categorizations
...
end
class Category < ActiveRecord::Base
belongs_to :categorizeable, polymorphic: true
has_many :categorizations
has_many :companies, :through => :categorizations, :source => :categorized, :source_type => 'User'
has_many :contacts, :through => :categorizations, :source => :categorized, :source_type => 'Contact'
...
end

Rails associations - how can I set up associations for different varieties of users?

I'm creating a web app which consists of schools, courses, students, and teachers.
A school can have many courses and a course has one teacher and many students.
The problem I am running into is that a single user could be a teacher of one course, but a student in another course (or even a student or teacher in a course in a different school). I don't want to create a model for teachers and a separate model for students because I would like to track all my users in one place. There is an enrollment table which lists which users are enrolled as students in a course.
I would like to do something like the following:
class School < ActiveRecord::Base
has_many :courses
has_many :students :through enrollments
has_many :teachers :through courses
end
class Course < ActiveRecord::Base
has_one :teacher
belongs_to :school
has_many :students :through enrollments
end
class User < ActiveRecord::Base
has_many :courses
has_many :schools
end
But if I have only a users table and not two separate students and teachers tables, this won't work.
Instead, I would have to do something like
class School < ActiveRecord::Base
has_many :users [that are teachers]
has_many :users :through enrollments [that are students]
end
How can I set up my model and associations to make this work?
Thanks.
Use inheritance.
Teachers and students are inherited from the users model. You can consult http://api.rubyonrails.org/classes/ActiveRecord/Base.html for further information. Be sure to create a "type" column or equivalent in your User table.
class User < ActiveRecord::Base
end
class Student < User
end
class Teacher < User
end
Rails will treat them individually, but they will still exist in the User table.Let me know if you need further assistance
I may have missed something, but it should work if you add the class_name to your relation with "User":
class School < ActiveRecord::Base
has_many :courses
has_many :students :through enrollments, :class_name => "User"
has_many :teachers :through courses, :class_name => "User"
end
class Course < ActiveRecord::Base
has_one :teacher, :class_name => "User"
belongs_to :school
has_many :students :through enrollments, , :class_name => "User"
end
class User < ActiveRecord::Base
has_many :courses
has_many :schools
end
Add a teachers_id column to courses and use belongs_to instead of has_one. Then add a class_name option.
class School < ActiveRecord::Base
has_many :courses
has_many :students :through enrollments
has_many :teachers :through courses
end
class Course < ActiveRecord::Base
belongs_to :teacher, :class_name => 'User'
belongs_to :school
has_many :students :through enrollments
end
class User < ActiveRecord::Base
has_many :courses
has_many :schools, :through enrollments
has_many :teachers, :through :courses
end

How to set up associations in Ruby on Rails?

I'm building a sample app for practice and am having trouble determining the best way to organize my models and associations. So let's just say I have 3 models:
Schools
Classes
Students
I want:
schools to have many classes
classes to have many students
classes to belong to a school
students to be enrolled in many classes in many different schools
The associations are making me dizzy, I'm not sure which ones to use. Help would be greatly appreciated.
Renamed class to course, as the class name Class is already taken. A join class such as enrollments would handle your many to many course <=> student relationship.
class School
has_many :courses
end
class Course
belongs_to :school
has_many :enrollments
has_many :students, :through => :enrollments
end
class Student
has_many :enrollments
has_many :courses, :through => :enrollments
end
class Enrollment
belongs_to :course
belongs_to :student
end
Your models should looks like this:
class School < ActiveRecord::Base
has_many :classes
has_many :students, :through => :classes
end
class Class < ActiveRecord::Base
belongs_to :school
has_and_belongs_to_many :students
end
class Student < ActiveRecord::Base
has_and_belongs_to_many :classes
end
Make sure your Student and Class tables have class_id and school_id columns respectively.
Also, Class is a reserved word in Rails, so it might cause problems (you might have to use a different name)
Though on first blush it would seem students should belong directly to class, class isn't really a true "has_and_belongs_to_many" replacement. For that I would use "enrollment". (Note with rails 3.1 you can now do nested :through calls.)
Here's a slightly more advanced implementation than the previous commenter's:
class School << ActiveRecord::Base
has_many :academic_classes
has_many :enrollments, :through => :academic_classes
has_many :students, :through => :enrollments, :uniq => true
end
class AcademicClass << ActiveRecord::Base
belongs_to :school
has_many :enrollments
end
class Enrollment << ActiveRecord::Base
belongs_to :academic_class
belongs_to :student
end
class Student << ActiveRecord::Base
has_many :enrollments
has_many :academic_classes, :through => :enrollments
has_many :schools, :through => :academic_classes, :uniq => true
end

Checking a related relationship once the instance is created

I have a schema where:
Students
has_and_belongs_to_many :courses
has_many :grades, :dependent => :destroy
has_many :assignments, :through => :grades
Courses
has_many :assignments, :dependent => :destroy
has_and_belongs_to_many :students
Assignments
belongs_to :course
has_many :grades, :dependent => :destroy
has_many :students, :through => :grades
Grades
belongs_to :student
belongs_to :assignment
I would like to add functionality whereby if a grade is added and the student does not belong to the course that the grade's assignment belongs to, then this relationship is made. Any suggestions as to the best way to do this? The grades_courses table does not have it's own model, will this need to be made?
A friend has suggested using after_create, but I don't know how to pass the parameters to this.
How about an observer on grades? Something like this
class GradeObserver < ActiveRecord::Observer
def after_create(grade)
unless grade.assignment.course.students.include?(grade.student)
grade.assignment.course.students << grade.student
end
end
end

Resources