I'm trying to represent a relationship between users in my application where a user can have many followers and can follow other users.
I would like to have something like user.followers() and user.followed_by()
Could you please tell me in details how to represent this using ActiveRecord?
Thanks.
You need two models, a Person and a Followings
rails generate model Person name:string
rails generate model Followings person_id:integer follower_id:integer blocked:boolean
and the following code in the models
class Person < ActiveRecord::Base
has_many :followers, :class_name => 'Followings', :foreign_key => 'person_id'
has_many :following, :class_name => 'Followings', :foreign_key => 'follower_id'
end
and corresponding in the Followings class you write
class Followings < ActiveRecord::Base
belongs_to :person
belongs_to :follower, :class_name => 'Person'
end
You could make the names clearer to your liking (i especially don't like the Followings-name), but this should get you started.
The twitter follower model differs from the friendship model in that you do not need permission from the person to follow them. Here I set up a lazy loading where the relationship is not fully defined in the person object.
/app/models/person.rb
def followers
Followership.where(:leader_id=>self.id).not_blocked
end
def following
Followership.where(:follower_id=>:self.id).not_blocked
end
has_many :followers, :class_name=>'Followership'
has_many :followed_by, :class_name=>'Followership'
/app/models/followership.rb
belongs_to :leader, :class_name=>'Person'
belongs_to :follower, :class_name=>'Person'
#leader_id integer
#follower_id integer
#blocked boolean
scope :not_blocked, :conditions => ['blocked = ?', false]
Related
I have a model called House and I want to be able to associate houses with each other to show recommendations.
So I would expect that given a house, I should be able to ask: house.recommended_houses. A house could be recommended for more than one house.
I was thinking on having a table that would store this association (I don't know the name yet), so it would have the following columns:
recommended_house_id
recommended_for_house_id
I am failing to understand how would I hook this up with my House model. What would the associations look like, and also what name should I be using for that join model?
This should get you started:
class House < ApplicationRecord
has_and_belongs_to_many :recommendations,
class_name: "House",
foreign_key: "recommended_by_id",
association_foreign_key: "recommendation_id"
end
What you're describing is called a self-referential association.
You can set up a join table (recommendations) and the associated model:
class Recommendation < ActiveRecord::Base
belongs_to :house
belongs_to :recommended_house, :class_name => 'House'
end
and then use has_many, :through relationships within the House model to set up the relationships you're looking for.
class House < ActiveRecord::Base
has_many :recommendations
has_many :recommended_houses, :through => :recommendations
has_many :inverse_recommendations, :class_name => "Recommendation", :foreign_key => "recommended_house_id"
has_many :recommended_by_houses, :through => :inverse_recommendations, :source => :house
end
Now you can use both house.recommended_houses and house.recommended_by_houses.
I'm having a trouble with grasping a proper relationship between two Rails/ActiveRecord classes.
I have a User, which can both create a Slip and simultaneously be an addressee of another slip. Each user can create any number of slips but only one user as the addressee of a given slip.
From the db perspective I have two integer (key) columns for 'user_id' (author) and 'addressee' in the slips table and no reference on the users table.
This is my current approach which is not working at all:
class User < ApplicationRecord
has_many :slips
belongs_to :slips, :foreign_key => 'addressee'
end
class Slip < ApplicationRecord
belongs_to :user
has_one :addressee, :through => :user
end
Please direct me to the proper way of binding these objects.
Thanks and have a nice day!
It should look something like this (the second one could just be called 'slip' but I've called it 'addressor_slip' to avoid confusion):
class User < ApplicationRecord
has_many :slips
has_one :addressor_slip, :class_name=> 'Slip', :foreign_key => 'addressee'
end
class Slip < ApplicationRecord
belongs_to :user
belongs_to :addressee, :class_name=> 'User', :foreign_key => 'addressee'
end
You could also create an association from User to User through :addressor_slip
Look at many to many relationships here: http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html
You're probably looking for has_and_belongs_to_many.
So I have the following models
User, Course, Order, Line_item
User (seller) has_many :courses (as the instructor, uploading them)
On the other hand...
User (buyer): has_many :orders
Order: has many :line_items
line_item: belongs_to :course
So I want a list of all courses purchased by a buyer, can I at this point use #user.courses to do so? How can I distinguish between buyer.courses and seller.courses?
Any help is appreciated. Thanks!
You need to use self-referential association for this.
#cousre.rb
Class Course < ActiveRecord::Base
belongs_to :sellar, :class_name => 'User', :foreign_key => 'sellar_id'
end
#order.rb
Class Order < ActiveRecord::Base
belongs_to :buyer, :class_name => 'User', :foreign_key => 'buyer_id'
end
I have a Friends model with user_id and friend_id...both are id's back to specific users.
What I'd like to able to do is something like this:
#relationship = Friend.find_by_user_id(current_user.id)
#relationship.friend.username
Where I can basically pull the user through the friend_id column in the same way I can do #relationship.user.username.
How would I setup my associations to pull that off?
Isn't this just a many-to-many situation.
I think there is a perfect solution in Many-to-many relationship with the same model in rails?
Hope this help!
Use class_name if your column doesn't reflect the convention expected:
class Friendship < ActiveRecord::Base
belongs_to :user
belongs_to :friend, class_name: 'User'
end
Note that I modified the model name to Friendship to better reflect the use of this model. Also, you can make it easier for yourself if you revise your User model to look like this:
class User < ActiveRecord::Base
has_many :friendships
has_many :friends, :through => :friendships
has_many :friendships_of, :class_name => 'Friendship', :foreign_key => :friend_id
has_many :friends_of, :through => :friendships_of, :source => :user
end
Now to see all the user's friends:
current_user.friends.map(&:username)
And to see who has 'friended' the user:
current_user.friends_of.map(&:username)
I have got a Database like this:
users
-id
user_cars
-user_id
-car_id
cars
-id
-model
-color
So a user can have multiple cars, and detailed information about the cars are in a big cars table. I also created the models with the relationships.
class User
has_many :user_cars
class User_car
belongs_to :user
belongs_to :cars
class Car
has_many :user_cars
Now I want to access the information for all the cars for one user. My first approach would be to get at least one information (i.e. color) from the cars table.
I tried this one, just as an example for accessing the middle table:
#user_id = current_user.user_cars.find(1).user_id
works! But when I try to access the cars table I always get an error.
#color = current_user.user_cars.cars.find(1).color
undefined method `cars' for #<ActiveRecord::Relation:0xaf92e8c>
So I think Im doin something easy very wrong...
When I know how to get access to the third table, I have to do it in that fashion, that I only get results for the user and not just only the first entry, maybe you guys can help me with that aswell. Thanks!
The issue in your example by the way is that belongs_to should be singular. Also, your order was wrong.
#color = current_user.user_cars.find_by_car_id(1).car.color
You should rewrite this to use a has_many through association:
class User
has_many :user_cars
has_many :cars, :through => :user_cars
class UserCar
belongs_to :user
belongs_to :car
You can then access the cars by doing:
current_user.cars
And the color by doing:
#color = current_user.cars.find_by_car_id(1).color
EDIT
After some debugging, it turns out that the Car model has a class property. Class is a reserved word in ruby. Be careful with naming your attributes!
Without has_many :through associations:
#color = current_user.user_cars.where(:car_id => 1).first.color
With them:
class User < ActiveRecord::Base
has_many :user_cars, :foreign_key => :user_id, :class_name => "UserCar", :inverse_of => :user
has_many :cars, :through => :user_cars
end
class UserCar < ActiveRecord::Base
belongs_to :user
belongs_to :car
end
class Car < ActiveRecord::Base
has_many :user_cars, :foreign_key => :car_id, :class_name => "UserCar", :inverse_of => :car
has_many :cars, :through => :user_cars
end
#color = current_user.cars.find(1).color
http://guides.rubyonrails.org/association_basics.html#the-has_many-through-association
:through defines a shortcut
:inverse_of defines a method (association) which represents current model in :class_name model
:class_name defines which model should be represented by :user_cars
:foreign_key tells which column in the target model's table represents current model (in table user_cars (or users_cars, depends on how you define the association, i think it should be user_cars in this example.. and users_cars for has_and_belongs_to_many)
Details on those are in the link above.