Rails has many and belongs to between two times with same models - ruby-on-rails

I am wondering how to do something so If someone knows I will be glad to hear. I have the following models
User
Usertype
Course
I have two types of users - student and teacher.
What I want to have is two tables
CourseTeacher - course_id, teacher_id
CourseStudent - course_id, student_id
My User model has usertype_id column. So I am wondering how to use has_many_and_belongs_to in that case because everything depends on usertype_id column in User model.

I think class inheritance is a cleaner way to model your domain logic:
class User < ActiveRecord::Base
end
class Student < User
end
class Teacher < User
end
Then the table would have an id and type column, greatly simplifying what you're trying to accomplish. Read the API docs to learn more: Single Table Inheritance

If you don't have ability to refactor, you can try using this approach:
Instead of 2 tables create one:
class CoursesUsers
belongs_to :course
belongs_to :user
end
And the decide yourself logic inside the user model (It seems like polymorphic to me)

Related

Devise and multiple users models

I'm fairly new to Rails and trying to setup an app that uses several types of users: Teacher, Student, Admin (and likely more to come).
The reason I want different models is because the attributes for the various users differ. For example, Teacher have topics taught, a profession, and a diploma. Whereas Student and Admin do not. Students can leave reviews of teachers, etc.
I thought of having a general User model for the general information such as name, email, and other contact information and each type of user would inherit of it:
class Admin < User
end
class Teacher < User
end
class Student < User
end
And so on.
I'm using Devise for authentication and used STI for differentiating between user roles through a role field in the table.
The thing is, where and how can I tell my app to generate a current_user of the right class when the user logs in? And where should I store the additional info on each model (ex the profession of a teacher). In the users table?
About the relationship with their objects, for example, a teacher has many topics he teaches. How can I make sure only teachers have topics and not students?
I've looked into CanCan but was utterly confused.
My advice is : DONT DO THAT ! You are mixing very different concerns and will end up with the infamous God Object.
User is here only for authentication, you should not mix it with your domain models. Teacher / Student / Admin etc should be separate models from User. You can eventually create a People table and have Teacher Student and Admin inherit from it.
class Student < Person
Or have a different table for each of them so there's no possible confusion (also someone might be both a Teacher and an Admin for example, separating stuff keeps your options open)
But whatever you choose keep User out of it !
If you want to tie a User to Teacher / Student / Admin use associations and give each of them a user_id.
class Student < ActiveRecord::Base
belongs_to :user
end
Please have a look into this link. Hope this may helpful to you:-
http://funonrails.com/2011/12/multiple-resources-registrations-with/
Also, you can manage relationship with their objects by making model(table) as polymorphic like:-
# Topic Model:
belongs_to :readable, :polymorphic => true
Also in topic model there are two more fields:-
readable_id and readable_type.
# Teacher Model:
has_many :topics, as: :readable
# Sturdent Model:
has_many :topics, as: :readable

Database organization for separating two different types of the same model

So I want my User model to have_many Skills. I want there to be two different categories for the skills: a wanted skill, and a possessed skill.
For example, a user can add a skill to their profile that they possess, such as HTML. They can also add a skill to their profile that they wish to learn, such as Ruby on Rails. On their profile it'll list their current skills and wanted ones, separately.
From a high level, what's the best way to architect this? I just want there to be 1 Skill model with no duplicates, but I want there to be a way for users to have the 2 separate groups of skills in the database.
You can use single table inheritance
class Skill < ActiveRecord::Base
end
class WantedSkill < Skill
belongs_to :user
end
class PossessesSkill < Skill
belongs_to :user
end
Your skills table should have a column called type where the type of the skill will be stored.
WantedSkill.create(:name => "html")
Above will save the record in the skills table with type 'WantedSkill'. You can retrieve it by
WantedSkill.where(:name => "html").first
your user associations can be like
class User < ActiveRecord::Base
has_many :wanted_skills
has_many :possessed_skills
end
You can read documentation here
A way to achieve this, you need two skill fields like: wanted_skill and possessed_skill
So, in Ruby on Rails you can have many references (with different names) to the same model, you only need to declare which class corresponds using class_name in the references, e.g.:
class User < ActiveRecord::Base
belongs_to :wanted_skill, class_name: 'Skill'
belongs_to :possessed_skill, class_name: 'Skill'
end

How do you get the type when using Table Per Type inheritance in Ruby on Rails?

I have a couple of classes that look like this:
Person {
id(PK)
first_name string
last_name string
}
class Employee {
person_id(FK)
job_description string
}
class Student {
person_id(FK)
school_name string
}
If I had a large list of People, how could I figure out what type each of them are without having to do
Student.where(person_id = person.id).any?
and
Employee.where(person_id = person.id).any?
for every "person" in the list?
I need to do a similar operation very often, so would Single Table Inheritance be a better choice?
It looks like what you're trying to implement is Class Table Inheritance.
(See earlier questions. eg. "Class Table Inheritance in Rails 3")
There are various gems trying to implement this,
and they each have their own opinions.
Fundamentally if all you know is the "person_id" then you will always need to look up the other tables to find which class it is.
The simplest way you can do this without changing anything fundamental is to use rails' has_one to create a cached relation between the two tables.
class Person
has_one :employee_details, class_name: "Employee"
has_one :student_details, class_name: "Student"
def employee?
employee_details.present?
end
def student?
student_details.present?
end
end
Importantly a Person can be both an employee and a student.
If that is not the case, then I suggest you look at Rails' Single Table Inheritance, or consider another way of implementing the same.
If it's Ruby on Rails (ActiveRecord)
class Person < ActiveRecord::Base
has_many :employees
has_many :students
end
class Employee
belongs_to :person
end
class Student
belongs_to :person
end
Person.find(person_id).students.any?
Person.find(person_id).employees.any?
Also, for the record, I am just answering the question as you phrased it. I think a better design would be to have a class called (Role) and have Employee and Student extend from that so you could have a many to many association to Role so a person could be both a student(s) and an employee(s) which is entirely possible

rails model relationship and migration

I have some problem trying to understand when building a rails app with several models and relation ships between them...
If I take a basic example like a model Group, a model User and a model Car
class Group < ActiveRecord::Base
has_many :users
end
class User < ActiveRecord::Base
belongs_to :group
has_many :cars
end
class Car < ActiveRecord::Base
belongs_to :user
end
Will those relation ship statements automatically create the following functions:
group.users
user.group
user.cars
car.user
It seems that we sometimes need to have to create "references" in migration (like adding a reference toward User in Car table) but is this always required ?
In this case, what is the difference of creating the migration and of adding the relationship statement in the models ? I sometimes have the feeling this is used for the same purpose.
Thanks a lot for your help,
Regards,
Luc
The association declarations are there for Rails only. You have to define the foreign keys (references) in the database, so that Rails can properly save the data.
Remember, despite all the magic, it's still backed by a relational database, so good practices there will pay off in the long run.

What should I do to make a Polymorphic Relationships in RoR?

I have a user table, and have a role column, that identify their role. Now, I want to add a "Student" table, that have the student's student number, and I also want to add a "Teacher", to store the teacher's salary.
Both the Student and Teacher are the subclass of User. Now, I added a role column already in the User table, "T" = Teacher, and "S" = Student. Now, I want to add "Student" and "Teacher" in the database. What should I do? Generate scaffold or migration only? Also, it is necessary to modify my models? or I just need to modify the controller only??
Thank you.
This sounds more like a job for Rails' single table inheritance. It's really easy to use. Instead of using a separate table to store roles. Inherit your student and teacher models from User.
for example:
User < ActiveRecord::Base; ... end
Student < User; ... end
Teacher < User; ... end
Rails automatically creates a type column and stores the class there.
User.all will return all users Student.all will return users where the type is matches Student and Teacher.all will do the same for all teachers.
You can read more about single table inheritance at the ActiveRecord documentation, and here.
As nuclearsandwich said, this is a situation that calls for rails STI (single table inheritance), not polymorphic associations.
Just to highlight the difference:
1) Singe table inheritance is used when you have different models that are very similar to each other with minor differences. STI lumps all models in the same database table, with fields (columns) for all the models that use this table. There is also a "type" field which indicates which model this record belongs to.
Your case is a perfect example of STI. You have user, student, and teacher models, they share a lot of common fields and functionality, you just want an extra field for the student and the teacher.
2) Polymorphic association is used when you have a model that will be associated with different models. For example, imagine you have an "Address" model. Also you have a "Company" and a "User" model, both of which can have an address.
In your Address model, you can specify
belongs_to :user
belongs_to :company
And then make sure if the address belongs to a company not to call address.user and vice-versa. However, a better way to do it would be through a polymorphic association. In your address model you do
belongs_to :addressable, :polymorphic => true
and in your user and company model you add
has_one :address, :as => :addressable
This allows the address model to polymorph (literally: transform into many) its association, and be connected with multiple different models through a single association.

Resources