Rails self-referential has_many through - ruby-on-rails

I'm trying to make a self-referential user class with three basic user types - parent, student, and tutor. A student belongs to a parent and can also belong to a tutor. Of course, the way I have it written, rails only recognizes the parent having students. User.students always returns empty if the user is a tutor, but it works when the user is a parent. Any ideas?
class User < ActiveRecord::Base
# Sets up the tutor has_many students assocation
has_many :tutees, :foreign_key=>"tutor_id",
:class_name=>"Relationship"
has_many :students, :through=>:tutees
# Sets up the student has_many tutors association
has_many :mentors, :foreign_key=>"student_id",
:class_name=>"Relationship"
has_many :tutors, :through=>:mentors
# Sets up the parent has_many students assocation
has_many :children, :foreign_key=>"parent_id",
:class_name=>"Relationship"
has_many :students, :through=>:children
# Sets up the student has_many parents
has_many :mommies, :foreign_key=>"student_id",
:class_name=>"Relationship"
has_many :parents, :through=>:mommies
The Relationship class:
class Relationship < ActiveRecord::Base
belongs_to :tutor, :class_name=>"User"
belongs_to :student, :class_name=>"User"
belongs_to :parent, :class_name=>"User"
end
The sections (parent, student, tutor) are each their own class as well. Basic user info is in the User class while data particular to tutors is in the Tutor class.

It is happening because of the same name (students) of relationships.
In your case,
has_many :students, :through=>:tutees
overrides by
has_many :students, :through=>:children
relation.
So you need to use different name then it will work.
-Ashish

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

Association for model - has_many :through

I have three models - Company, User and CompanyUser. The associations are as follows.
Company.rb
has_many :company_users
has_many :users, :through => :company_users
User.rb
has_many :company_users, :dependent => :destroy
belongs_to :company
CompanyUser.rb
belongs_to :company
belongs_to :user
For fetching current_user.company, what moddifications are to be made in the model association?
Any help would be appreciated.
It should be:
has_many :companies, through: :company_users
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.
So if you are creating three models and making a has_many :through association I believe that User will have many Companies and Company will have many Users.
But if you need that the user belongs to only one company instead of creating the third model save the company_id in the users table itself.
Update:
Now as your scenario is A company can have may users and User belongs to a single company, you need two models: User and Company. Your User model should have an attribute company_id and then company_id should be saved in users table only. Then the associations as follows:
class User < ActiveRecord::Base
belongs_to :company
end
class Company < ActiveRecord::Base
has_many :users
end
Then you can do current_user.company
You can get more information on associations in the RailsGuides
According to the associations you have taken,
user already have as association with the company through the Company User model, so user may have many companies according to your associations.
so,
class User < ActiveRecord::Base
has_many :company_users, :dependent => :destroy
has_many :companies, :through => :company_users
end
current_user.companies will give you the companies.
But if you need only one company for a user then,
class User < ActiveRecord::Base
belongs_to :company
end
take belongs_to company and save company_id in users table,
then you can call,
`current_user.company`
According to your logic,
I think you may need to create a new variable session current_company_user which is object CompanyUser.
And then, to fetch company by :
current_company_user.company

User model with relationship table

I have two models User and UserRelation. The case is that User has several related users with himself(recommended by him), but he has only one person related_to(person who recommended him).
I would like to return from User object collection of recommended users and user who recommended him. I have written association for returning users collection and it works but I have no idea how should I write has_one association.
I get this error:
ActiveRecord::HasOneThroughCantAssociateThroughCollection: Cannot have a has_one :through association 'User#relation' where the :through association 'User#user_relations' is a collection. Specify a has_one or belongs_to association in the :through option instead
User model:
class User < ActiveRecord::Base
has_many :user_relations
has_many :related_users, through: :user_relations, source: :related_user
has_one :relation, through: :user_relations, source: :user
end
UserRelation model:
class UserRelation < ActiveRecord::Base
belongs_to :user
belongs_to :related_user, class_name: 'User'
end
UserRelation columns:
user_id
related_user_id
My choice would be to put a foreign key in your User table for the possible related_to field.
If the requirement is that it can only be one (or none) then why not?
You still keep the other "user_relations" for all other types. All the time in rails, we map to the same entity in different ways. It's not uncommon at all

How make categories relationships with several model?

I have next models: Articles, Announcements, Catalogs and Media.
For item of every model I need to create a subcategory and a category. I will plan to create a relationship table with two columns: parend_id and child_id, and a column for every model with category_id.
How many relationship models I should create?
One for all?
Or one relationship model for every model?
No need to create a relationship model instead just use belongs_to relationship
because you said following i guess belongs_to relations should do it
For item of every model I need create subcategory and category.
So just add subcategory_id and category_id in your tables: Articles, Announcements, Catalogs and Media and establish has_many belongs_to relationship
EDIT But if you insist for relationship model then I would suggest to use one relationship model for every model.
Last EDIT: I really think you should use belongs_to, has_many relation
Class Article < ActiveRecord::Base
belongs_to :category
belongs_to :subcategory
end
class Category < ActiveRecord::Base
has_many :articles
# the same relation(has_many) will be for Announcements, Catalogs and Media
has_many :subcategories
end
class Subcategory < ActiveRecord::Base
has_many :articles
belongs_to :category
end
In this way you can get all articles using category.subcategories.articles
If the category has only one Subcategory then change the relation between them to has_one and your syntax will become category.subcategory.articles
I would personally use a has_many :through relationship with a polymorphic association in a single join table:
#app/models/article.rb
Class Article < ActiveRecord::Base
has_many :categorizable_categories
has_many :categories, through: :categorizable_categories
end
class Article < ActiveRecord::Base
has_many :tags, as: :taggable,dependent: :destroy
has_many :categories, through: :tags
end
class Category < ActiveRecord::Base
has_many :tags, dependent: :destroy
has_many :articles, through: :tags, source: :taggable, source_type: 'Article'
end
class Tag < ActiveRecord::Base
belongs_to :taggable, polymorphic: true
belongs_to :category
end
This will allow you to call the categories for each model with the likes of #article.categories
To achieve the parent & child categories, I'd recommend using something like the Ancestry gem - you'd set up an ancestry column in your join table - basically allowing you to create relations between a model's categories directly

Can't show select box

I have 3 models:
Lending
Equipment
Category
Lending belongs_to equipment
Equipment belongs_to :category
Equipment has_many :lendings
Category has_many :equipments
I want to show a selectbox in lending's form with the categories.But there's not any association between Lending and Category models.I can't see an association between these two models(Lending and Category) but with Equipment and Category yes.
How do I do that? Ah I'm using simple form!
Excuse my english!
you have generated a textbook example of has_many :through:
http://guides.rubyonrails.org/association_basics.html#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 < ActiveRecord::Base
has_many :appointments
has_many :patients, through: :appointments
end
class Appointment < ActiveRecord::Base
belongs_to :physician
belongs_to :patient
end
class Patient < ActiveRecord::Base
has_many :appointments
has_many :physicians, through: :appointments
end
You should be using delegation in this case. Add this line to your lending.rb file.
delegate :category, to: :equipment
This will return the concerned category.

Resources