Has many through relationship in rails - ruby-on-rails

I am using facebook api to fetch users from fb.
I want to store the users in my model User
I am using has many through relationship to store users
User model relationship I have in my user model.
has_many :friends, :through => :user_friends, :class_name => "User", :foreign_key => "friend_id"
User friends model intermediate table to fetch friends of a user.
belongs_to :user
belongs_to :user, :foreign_key => "friend_id"
User friends has user_id and friend_id columns I added those in migration.
I get an error when I use .friends on a user object.
ActiveRecord::HasManyThroughAssociationNotFoundError: Could not find the association :user_friends in model User
can anyone help with this?
Thanks in advance.

You need to check Self-Referential Association. Apparently you are missing some concepts. You can not add 2 associations with the same name in a single model, (only one of them will respond).
You should add has_many :user_friends, but you will still be missing the other side of the association, check this example:
# user.rb
has_many :user_friends
has_many :friends, :through => :user_friends
has_many :inverse_friendships, :class_name => "UserFriend", :foreign_key => "friend_id"
has_many :inverse_friends, :through => :inverse_friendships, :source => :user
# user_friends.rb
belongs_to :user
belongs_to :friend, :class_name => "User"

Add has_many :user_friends before the has_many :through line

Try This:
User Model:
has_many :user_friends
has_many :friends, :through => :user_friends, :class_name => "User", :foreign_key => "friend_id"
Friends Model:
has_many :user_friends
has_many :users, through: :user_friends
User Friends Model
belongs_to :user
belongs_to :friend, :foreign_key => "friend_id"

Related

How would you represent this logic in models and migration

This has probably been asked but I am not even sure how to phrase this suitable for querying.
I wish to call user1.friends (user1 is an instance of the User model) which returns a list of users who all include user1 as one of their friends.
I am not sure where to even start with this one.
What would be my columns for the friends table? Should there even be a friends table?
Maybe you could use this RailsCasts
models/user.rb:
has_many :friendships
has_many :friends, :through => :friendships
has_many :inverse_friendships, :class_name => "Friendship", :foreign_key => "friend_id"
has_many :inverse_friends, :through => :inverse_friendships, :source => :user
models/friendship.rb
belongs_to :user
belongs_to :friend, :class_name => "User"

Get data through many to many relations

I have 3 tables:
User class
User has_many :project_assignments
User has_many :projects, through: :project_assignments
ProjectAssignment class
ProjectAssignment belongs_to :user
ProjectAssignment belongs_to :project_owner, class_name: 'User', foreign_key: 'user_creator_id'
ProjectAssignment belongs_to :project
Project
has_many :project_assignments
has_many :users, through: :project_assignments
ProjectAssignment has the columns:
project_id, user_id, creator_user_id
I want to get all the projects, for a user through creator_user_id
ex: current_user.created_projects
The query: ProjectAssignment.where(creator_user_id: current_user.id)
Can it be done when defining the relations in the models, the same as I did with projects but the foreign_key should be creator_user_id
I think you just need another couple of associations in User which leverage the creator_user_id field (as opposed to user.projects which will return the projects the user is a member of)
Try this -
#in User class
has_many :owned_project_assignments, :class_name => "ProjectAssignment", :as => :project_owner, :foreign_key => "user_creator_id"
has_many :owned_projects, :through => owned_project_assignments, :class_name => "Project", :source => :project, :as => :project_owner
the :source and :as options can be a bit tricksy, so this might not work, it's just off the top of my head...
In my case this was the correct solution:
has_many :owned_project_assignments, class_name: "ProjectAssignment", foreign_key: 'user_creator_id'
has_many :owned_projects, through: :owned_project_assignments, source: :project

Correct association for Twitter-style posts by followed users in rails

I'm trying to list all the posts made by a user's followed users, and not sure how to correctly set up the associations. This has been discussed in various forms but I can't find a definitive answer that works in this case. My current associations are as follows:
user.rb:
has_many :followers, :class_name => 'UserFollower', :foreign_key => 'user_id'
has_many :following, :class_name => 'UserFollower', :foreign_key => 'follower_id'
has_many :posts
user_follower.rb:
belongs_to :user
belongs_to :follower, :class_name => 'User'
post.rb
belongs_to :user
I want to be able to do something like current_user.following_user_posts. So I'm trying to define an association in my user.rb something like:
has_many :following_user_posts, :through => :following
Obviously this isn't quite right, but where am I going wrong?
Michael hartle answers this exactly in his tutorial using his Micropost.from_users_followed_by method http://ruby.railstutorial.org/chapters/following-users#sec-a_first_feed_implementation
Figured this out, seems like a simple problem but the terminology makes it quite confusing. I have the following in by user.rb:
has_many :user_followers
has_many :followers, :through => :user_followers, :source => :follower #the users that are following this user
has_many :user_followings, :class_name => 'UserFollower', :foreign_key => "follower_id"
has_many :following, :through => :user_followings, :source => :user #the users that this user is following
has_many :following_user_posts, :through => :user_followings, :source => :posts
And in my user_follower.rb:
belongs_to :user
belongs_to :follower, :class_name => 'User'
has_many :posts, :through => :user, :source => :posts
The resulting query uses 2 inner joins - I have no idea how well this will scale but its working fine for me on development. So now, I can simply use current_user.following_user_posts

What is the best way to handle 4 way relation between 2 models?

I have two models: Company and User
This is the situation:
Company can follow another company
User can follow a company
User can follow another user
What is the best way to define the relationships and how will the join model look like?
Also, are there any best practises when addressing such situations?
Update
Sorry, to have not mentioned this earlier. I am aware of the various relationship types available. My question is 'which is the best fit'?
Regarding your question I would suggest you to go through couple of Railscasts videos:
http://railscasts.com/episodes/47-two-many-to-many
http://railscasts.com/episodes/154-polymorphic-association
And this is described very well on RubyonRails website
http://guides.rubyonrails.org/association_basics.html
I would say look these for your case:
http://guides.rubyonrails.org/association_basics.html#the-has_many-through-association
http://guides.rubyonrails.org/association_basics.html#the-has_and_belongs_to_many-association
I hope this will help you.
Thanks to polymorphic associations, we can put all relations into one table which like this:
create_table :follows do |t|
t.references :followable, :polymorphic => true
t.references :followed_by, :polymorphic => true
end
Then the models are:
class User < ActiveRecord::Base
has_many :following_objects, :class_name => 'Follow', :as => :followed_by
has_many :followed_objects, :class_name => 'Follow', :as => :followable
end
class Company < ActiveRecord::Base
has_many :following_objects, :class_name => 'Follow', :as => :followed_by
has_many :followed_objects, :class_name => 'Follow', :as => :followable
end
class Follow < ActiveRecord::Base
belongs_to :followable, :polymorphic => true
belongs_to :followed_by, :polymorphic => true
end
Sorry for the ugly names.
A basic idea would be to use two self-referencing assocations:
User -> Friendship <- User
Company -> Partnership <- Company
models/user.rb
has_many :friendships
has_many :friends, :through => :friendships
has_many :inverse_friendships, :class_name => "Friendship", :foreign_key => "friend_id"
has_many :inverse_friends, :through => :inverse_friendships, :source => :user
models/friendship.rb
belongs_to :user
belongs_to :friend, :class_name => "User"
models/company.rb
has_many :partnerships
has_many :partners, :through => :partnerships
has_many :inverse_partnerships, :class_name => "Partnership", :foreign_key => "partner_id"
has_many :inverse_partners, :through => :inverse_partnerships, :source => :company
models/partnership.rb
belongs_to :company
belongs_to :partner, :class_name => "Company"
And one many-to-many assocation:
User -> CompanyUser <- Company
models/user.rb
has_and_belongs_to_many :companies
models/company.rb
has_and_belongs_to_many :users
So for this implementation you will need 5 tables (users, friendships, companies, partnerships and companies_users) if you are using a RDBMS.
You can get a nice example in this screencast:
http://railscasts.com/episodes/163-self-referential-association

has_many association with non-traditional data model

I'm struggling with a has_many association. I have a diary application. The model players are as follows:
User
UserFriend
UserFoodProfile
I want to be able to get at all the foods that a user's friends have eaten. So, I want to be able to get: current_user.friends.profiles
I've setup the associations properly so far so that I'm able to access current_user.friends, but now I want to be able to get all the friend's entries as well over the last 30 days.
Here are my models
class User < ActiveRecord::Base
cattr_reader :per_page
##per_page = 20
has_many :user_food_profiles
has_many :preferred_profiles
has_many :food_profiles, :through => :user_food_profiles
has_many :weight_entries
has_one :notification
has_many :user_friends
has_many :friendships, :class_name => "UserFriend", :foreign_key => "friend_id"
has_many :friends, :through => :user_friends
class UserFriend < ActiveRecord::Base
belongs_to :user
belongs_to :friend, :class_name => "User", :foreign_key => "friend_id"
class UserFoodProfile < ActiveRecord::Base
belongs_to :user
belongs_to :food_profile
belongs_to :post
The UserFriend model is setup the following way:
id
user_id
friend_id
friend_name
I want to connect to user_food_profiles from friend so that I can get a user's friend's current user_food_profiles as "entries" but everything I've tried hasn't worked. How would I setup this association?
Tried to do:
UserFriend: has_many :user_food_profiles, :as => 'entries'
UserFoodProfile: belongs_to :friend, :foreign_key => 'friend_id'
Any ideas on how to make this work? Tempted to create a custom finder_sql but I'm sure this can work with associations.
Isn't a "friend" just another user that's in the database?
Let your UserFriend be a many_to_many relationship (either with "has_and_belongs_to_many" or "has_many :through"): each user can have several users as friends.
You can then link those user_ids (which could be in the many_to_many table called 'friend_id' if you like) to their foodprofile without a problem, since it is using the same link as user.foodprofile .
This is the line I see being the problem:
class User < ActiveRecord::Base
# <snip/>
has_many :friendships,
:class_name => "UserFriend",
:foreign_key => "friend_id"
I'm assuming that you're using a join table here called user_friend. That would mean that the foreign key there should be "user_id".
Now, unless you're going to store extra metadata in that UserFriend model, it's not required — you can get away with a self-referential has_and_belongs_to_many relationship like so:
has_and_belongs_to_many :friends,
:class_name => "User",
:join_table => "user_friends",
:foreign_key => "user_id",
:association_foreign_key => "friend_id"
Doing this, all you have to do is user.friends.profiles quite easily.
Now, if the relationship is bi-directional it gets a bit more complex, but I feel like this should at least get you started along the way.

Resources