How would you represent this logic in models and migration - ruby-on-rails

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"

Related

Problems grouping has_many through collection

I'm having a problems with :group and :uniq tags as an option to has_many through collection definition. I have many triple model associations defined on my system and I want to list elements grouped to avoid (the actual) repetition. My main model looks like that:
class Trip < ActiveRecord::Base
belongs_to :agent
has_many :trips_destinations, :class_name => "TripsDestination"
has_many :destinations, :through => :trips_destinations
has_and_belongs_to_many :vibes, join_table: :trips_vibes
has_and_belongs_to_many :verbs, join_table: :trips_verbs
has_many :trips_destinations_activities, :class_name => "TripsDestinationsActivity"
has_many :activities, :through => :trips_destinations_activities, :uniq => true
has_many :trips_destinations_hotels, :class_name => "TripsDestinationsHotel"
has_many :hotels, :through => :trips_destinations_hotels
has_many :trips_destinations_recommended_places, :class_name => "TripsDestinationsRecommendedPlace"
has_many :recommended_places, :through => :trips_destinations_recommended_places
has_many :trips_destinations_transportations, :class_name => "TripsDestinationsTransportation"
has_many :transportations, :through => :trips_destinations_transportations
...
...
end
Anyone know how to list they why avoiding repetition given the pair [trip_id, destination_id]?
And why they are repeated?
My rails version is 4 and I the image below shows the error message when passing grouping options to has_many relation.
Please help!
Your syntax for uniq is not correct for Rails 4.
has_many :activities, -> { uniq }, :through => :trips_destinations_activities
Unique now has scope syntax.

Has many through relationship in 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"

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

How do I set up a directed many-to-many self-join using :through?

I'm setting up a Rails project for a client, and they want Users (a model) to be able to follow each other (as in Twitter). They also want to be able to keep track of when one user started following another.
Since I need to keep track of the creation date, I figured, a has_many X, :through => Y relation would be the way to go, so the Y will keep track of the date it was created.
I have my Follow model set up:
class Follow < ActiveRecord::Base
attr_accessible :actor_id, :observer_id, :follower, :followee
attr_readonly :actor_id, :observer_id, :follower, :followee
belongs_to :follower, :class_name => 'User', :foreign_key => :observer_id
belongs_to :followee, :class_name => 'User', :foreign_key => :actor_id
validates_presence_of :follower, :followee
validates_uniqueness_of :actor_id, :scope => :observer_id
end
The question is how do I set up the relations in the User model?
Ideally I'd like it to have the following:
:follows would be the associated Follow objects where self is the follower (observer_id)
:followed would be the associated Follow objects where self is the followee (actor_id)
:following would be the associated User objects where self is the follower (observer_id)
:followers would be the associated User objects where self is the followee (actor_id)
I'm not sure how to write the has_many :through parts, though? Should I be using :source => X or foreign_key => X? And which key (actor_id or observer_id) should I put in each?
Edit: I'm currently doing this
has_many :follows, :foreign_key => :observer_id
has_many :followed, :class_name => 'Follow', :foreign_key => :actor_id
has_many :following, :class_name => 'User', :through => :follows, :source => :followee, :uniq => true
has_many :followers, :class_name => 'User', :through => :follows, :source => :follower, :uniq => true
and it's mostly working. All of them except :followers work fine, but user.followers is doing something weird. It seems like it's checking whether user is followING someone, and if they are then user.followers returns an array containing only user; if they're not, it returns an empty array.
Does anyone have any advice?
It looks like this is the correct format:
has_many :follows, :foreign_key => :observer_id
has_many :followed, :class_name => 'Follow', :foreign_key => :actor_id
has_many :following, :class_name => 'User', :through => :follows, :source => :followee, :uniq => true
has_many :followers, :class_name => 'User', :through => :followed, :source => :follower, :uniq => true
For Rails newbies, the :uniq => true is important (as I discovered while doing this) because it keeps has_many X, :through => Y relations from returning duplicates (that is, without it, you might get multiple distinct objects, each with their own object ID, all referring to the same record/row).

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

Resources