User model with relationship table - ruby-on-rails

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

Related

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

Double entry table in rails

I would like to create a double entry table form according two models.
For now I'm able to create a simple table with the members of a communities
on the columns, I must add the informations of an other model, like this :
My models :
Community
has_many :memberships
Membership
belongs_to :user
belongs_to :community
User
has_many ::memberships
has_many :skills
Skill
belongs_to :user
belongs_to :community
I there some gem existing to make a double entry table or is it easier to make it from scratch? if so, how can I begin ?
It seems like you would benefit from a through relationship here.
Instead of referencing community directly from the skill table, you could do:
Skill
belongs_to :user
has_many :communities, :through => :user
On user, add:
has_many :communities, :through => :memberships
Wouldn't this get the link between skill and community that you would like?
As Jay mentioned, you would benefit from a has_many :through relationship, or maybe a has_and_belongs_to_many relationship; whether it's the actual solution we'll have to see:
#app/models/user.rb
Class user < ActiveRecord::Base
has_many :memberships
has_many :skill_users
has_many :skills, through: :skill_users
end
#app/models/skill_user.rb
Class SkillUser < ActiveRecord::Base
belongs_to :skill
belongs_to :user
end
#app/models/skill.rb
Class Skill < ActiveRecord::Base
has_many :skill_users
has_many :users, through: :skill_users
end
This will allow you to associate each user (note that members are different than users) with specific skills without using double-entries in your tables
Relational
The basis of what you're seeking can be found in Relational Databases
These work by storing data in single instances, and linking to other data through foreign_keys. These foreign keys are things such as user_id etc:
(more information here)
This means instead of populating the same data twice, it is correct to reference that data from other models, as required. This is where join models come in
Join Model
Join models allow you to "link" two pieces of data through a join model:
For you, it means storing your skills in its own model, and linking users with skills on a join model (I've called skill_user.rb). This means that you'll be able to call your user's skills like this:
#user.skills #-> goes through the join model

Method to give number of favorites in has_many through relationship

I have a User model where the users can "favorite" each other. I'm achieving this through a Favoriting model as a has_many through relationship to reference User to itself:
class User < ActiveRecord::Base
has_many :favoriting
has_many :favorites, through: :favoritings, source: :favorited
has_many :favoriteds, class_name: "Favoriting", foreign_key: "favorited_id"
has_many :favoriters, through: :favoriteds, source: :user
...
end
class Favoriting < ActiveRecord::Base
belongs_to :user
belongs_to :favorited, :class_name => 'User'
...
end
This all works great. I can do u.favorites and get a user's favorites, and I can do u.favoriters to get the users that have favorited u. I can also do u.favorites_count to get the number of favorites.
However, I can't do u.favoriters_count to get the number of users that have favorited u.
Any idea if there is access to a built-in method for favoriters_count or even favoriteds_count with this type of DB relationship? I could write my own but would rather keep the code base as simple and "Rails-y" as possible.
Have you considered adding a counter_cache alongside with a favoritings_count column?
No, the methods added by has_many are listed in 4.3.1 of http://guides.rubyonrails.org/association_basics.html and do not include a method by this name.

Creating a many-to-many relation in Rails

So I'm Rails n00b and I want to create a "favorites" relationship such that a User can have many favorite Item. I'm not entirely sure how to do this, this is how I'm going to try but I'm not sure if this is a good practice at all:
class User < ActiveRecord::Base
has_many :favorites
//other code
end
class Favorite < ActiveRecord::Base
belong_to :user
has_one :item
end
class Item < ActiveRecord::Base
belongs_to :item
end
Is this a good way to do it? Should I be using has_and_belongs_to_many ?
I'm specially concerned in the following scenario: Say a user has 100 favorite items.
When I do a User.find(id) will I also be retrieving the 100 favorites and the 100 Items?
In case it's important: ruby version 1.9.3, rails version 3.2.11
Can you try has_many => :through?
class User < ActiveRecord::Base
has_many :favorites
has_many :items, :through => :favorites
//other code
end
In your case has_many :through is definitely the way to go. I would recommend reading: http://guides.rubyonrails.org/association_basics.html
Of particular interest with regard to your question:
2.8 Choosing Between has_many :through and has_and_belongs_to_many
Rails offers two different ways to declare a many-to-many relationship between models. The simpler way is to use has_and_belongs_to_many, which allows you to make the association directly:
class Assembly < ActiveRecord::Base
has_and_belongs_to_many :parts
end
class Part < ActiveRecord::Base
has_and_belongs_to_many :assemblies
end
The second way to declare a many-to-many relationship is to use has_many :through. This makes the association indirectly, through a join model:
class Assembly < ActiveRecord::Base
has_many :manifests
has_many :parts, :through => :manifests
end
class Manifest < ActiveRecord::Base
belongs_to :assembly
belongs_to :part
end
class Part < ActiveRecord::Base
has_many :manifests
has_many :assemblies, :through => :manifests
end
The simplest rule of thumb is that you should set up a has_many :through relationship if you need to work with the relationship model as an independent entity. If you don’t need to do anything with the relationship model, it may be simpler to set up a has_and_belongs_to_many relationship (though you’ll need to remember to create the joining table in the database).
You should use has_many :through if you need validations, callbacks, or extra attributes on the join model.
It is better than using has_and_belongs_to_many.
When I do a User.find(id) will I also be retrieving the 100 favorites
and the 100 Items?
No. You'll just get the user object.
Update:
Calling User.include(:favourites, :items).find(id) will get you joined tables in case you want to make many calls to items table from user object.

Rails self-referential has_many through

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

Resources