Mr X likes only one post made by Mr Y
How can I create a relationship between Mr X and Mr Y to see the Mr Y's posts? (to see the suggested posts)
user.rb
has_many :posts
has_many :liked_posts, through: :liked, source: :post
post.rb
def liked_by?(user)
likes.where(user: user).any?
end
likes.rb
# id :integer not null, primary key
# user_id :integer not null
# like_id :integer not null
Should I use uniq ?
I'm not 100% certain if you mean this, but in case you want to relate User with Post through Like then proceed as:
user.rb
has_many :posts
has_many :likes
has_many :liked_posts, through: :likes
post.rb
has_many :likes
def liked_by?(user)
self.likes.where(user: user).any?
end
likes.rb
belongs_to :user
belongs_to :post
You'd have to add the respective database migrations to add the attributes to likes
Related
In my Post model, I have
has_many :followers
In my Follower model, I have
belongs_to :model
belongs_to :owner,polymorphic: true
In my User and Admin devise models, I have
has_many :followers,as: :owner
Requirement: I want to have something like Post.owners and it should return me a list of all users and/or admins that are following this post.
I'm not sure, but I think that AR doesn't provide a way to load polymorphic associations in just one query. But you can use:
post = Post.find(1)
post_followers = post.followers.includes(:owner)
post_owners = post_followers.map(&:owner)
The solution you're looking for is polymorphic has many through. You can add these lines in your model of User and Admin.
has_many :followers
has_many :posts, through: :followers, source: :owner, source_type: 'Owner'
I think you want something like this:
class Post < ApplicationRecord
belongs_to :owner, polymorphic: true
end
class User < ApplicationRecord
has_many :posts, as: :owner
end
class Follower < ApplicationRecord
has_many :posts, as: :owner
end
From an instance of your User you can then retrieve their posts with #user.posts
The same goes for your Follower, #follower.posts
If you want to get to the parent of your post instance, you can do so via #post.owner. To make this work, however, we need to set up the schema correctly by declaring both a foreign key column and a type column in the model that declares the polymorphic interface using the references form:
class CreatePosts < ActiveRecord::Migration[5.0]
def change
create_table :posts do |t|
# your attribs here
t.references :owner, polymorphic: true, index: true
end
end
end
I have a polymorphic association in my application and I want to be able to count the number of users in a group, and list the users in each group. How can I achieve this?
class Group < ApplicationRecord
has_many :user_groups
has_many :users, through: :user_groups
end
class User < ApplicationRecord
has_many :user_groups
has_many :groups, through: :user_groups
end
class UserGroup < ApplicationRecord
belongs_to :user
belongs_to :group
end
I at the moment I can call User.first.groups however I am not able to call User.groups.all and User.all.groups but none of these work.
First off, that's not a polymorphic association. Just FYI.
It's hard to know what you're asking, because to count the users in a group, you do:
group.users.count
When you say, 'list them', do you mean in a view? That would be something like:
<%- group.users.each do |user| %>
# do something with user
<% end %>
Just to expand on the comment, if the class Image had a polymorphic belongs_to association, that might look something like:
# == Schema Information
#
# Table name: images
#
# id :integer not null, primary key
# imageable_id :integer
# imageable_type :string
# created_at :datetime not null
# updated_at :datetime not null
#
class Image < ApplicationRecord
belongs_to :imageable, polymorphic: true
end
As you can see, the Image class has the attributes of imageable_id and imageable_type. Then, if you wanted to have Document have many images, you would same something like:
class Document < ApplicationRecord
has_many :images, as: :imageable
end
Then you could do:
image.imageable
To get the object that the image belongs to. To get all the images for a document, then simply:
document.images
I wanted to know the best way to implement the following:
Users can create a Post and each Post is associated with a US City and State.
I wanted to have a form where there is a dropdown box that a user can select the State and select the relevant City for example: [Hollywood] [California].
I have setup a State and City model.
The State model:
# == Schema Information
#
# Table name: states
#
# id :integer not null, primary key
# name :string default(""), not null
# short :string default(""), not null
# created_at :datetime not null
# updated_at :datetime not null
#
class State < ApplicationRecord
has_many :cities
end
The City model:
# == Schema Information
#
# Table name: cities
#
# id :integer not null, primary key
# name :string
# state_id :integer
# created_at :datetime not null
# updated_at :datetime not null
#
# Indexes
#
# index_cities_on_state_id (state_id)
#
class City < ApplicationRecord
belongs_to :state
end
With the Post model
# == Schema Information
#
# Table name: posts
#
# id :integer not null, primary key
# title :string default(""), not null
# body :string default(""), not null
class Post < ApplicationRecord
end
With the Post model I thought I would to a belongs_to and has_many association with references/foreign key setup like:
class Post < ApplicationRecord
belongs_to :city
belongs_to :state
end
class City < ApplicationRecord
belongs_to :state
has_many :posts
end
class State < ApplicationRecord
has_many :cities
has_many :posts
end
The view would use a form_for with a grouped_collection for cities and collection for the states but I don't think this is a good implementation because:
Selecting the city already as the association with the state. It seems redundant having the user select both model options?
The dropdown box in view will load 60000 city records and it will slow down the browser.
I wanted to know if a Polymorphic association would fit my use case and if someone can forward me in the right direction.
My thoughts: I was thinking something where the user selects the the State in a dropdown box eg. California, but enters the city in a text field and if the city does not exists in Cities table it create it, otherwise it will link to it?
Thanks for your help.
What you want is a has_one through: association. This indirect relation tells rails to join through another association and removes the need for a duplicated foreign key.
class Post < ApplicationRecord
belongs_to :city
has_one :state, through: :city
end
To create a full hierarchy you would do it like so:
class Post < ApplicationRecord
belongs_to :city
has_one :state, through: :city
has_one :country, through: :state
end
class City < ApplicationRecord
belongs_to :state
has_one :country, through: :state
has_many :posts
end
class State
belongs_to :country
has_many :cities
has_many :posts, through: :cities
end
class Country < ApplicationRecord
has_many :states
has_many :cities, through: :states
has_many :posts, through: :cities
end
Polymorphic associations are a very different thing altogether - its used when an association can be to different models. In this example a Comment can be belong to a Post or a Page.
class Comment < ApplicationRecord
belongs_to :commentable, polymorphic: true
end
class Post < ApplicationRecord
# this tells AR to look at the `commentable` association on
# Comment.
has_many :comments, as: :commentable
end
class Page < ApplicationRecord
has_many :comments, as: :commentable
end
I am trying to set up a polymorphic has-many-through relationship with ActiveRecord. Here's the end goal:
Users can belong to many organizations and many teams
Organizations have many users and many teams
Teams have many users and belong to an organization
I am trying to use has-many-through instead of has-and-belongs-to-many, since I need to associate some information along with the relationships (like user role in the organization or team), so I made a join table Membership.
How would I implement this?
I would design the schema like this:
Organization has many Team
Team has many TeamMember
User has many TeamMember
TeamMember belongs to User and Team
The models will be:
organization.rb
class Organization < ActiveRecord::Base
has_many :teams
has_many :team_members, through: :teams
has_many :users, through: :team_members
end
team.rb
class Team < ActiveRecord::Base
belongs_to :organization # fk: organization_id
has_many :team_members
has_many :users, through: :team_members
end
user.rb
class User < ActiveRecord::Base
has_many :team_members
has_many :teams, through: :team_members
has_many :organizations, though: :teams
end
team_member.rb
class TeamMember < ActiveRecord::Base
belongs_to :team # fk: team_id
belongs_to :user # fk: user_id
attr_accessible :role # role in team
end
So, compare with your requirements:
Users can belong to many organizations and many teams
=> Okay
Organizations have many users and many teams
=> Okay
Teams have many users and belong to an organization
=> Okay
Btw, we don't use any polymorphic here, and TeamMember stands for Membership in your early idea!
For polymorphic association,
class User
has_many :memberships
end
class Team
belongs_to :organization
has_many :memberships, :as => :membershipable #you decide the name
end
class Organization
has_many :memberships, :as => :membershipable
has_many :teams
end
class Membership
belongs_to :user
belongs_to :membershipable, polymorphic: true
end
Note that User is indirectly associated to Team and Organization, and that every call has to go through Membership.
In my projects, I use a Relationship class (in a gem I've named ActsAsRelatingTo) as the join model. It looks something like this:
# == Schema Information
#
# Table name: acts_as_relating_to_relationships
#
# id :integer not null, primary key
# owner_id :integer
# owner_type :string
# in_relation_to_id :integer
# in_relation_to_type :string
# created_at :datetime not null
# updated_at :datetime not null
#
module ActsAsRelatingTo
class Relationship < ActiveRecord::Base
validates :owner_id, presence: true
validates :owner_type, presence: true
validates :in_relation_to_id, presence: true
validates :in_relation_to_type, presence: true
belongs_to :owner, polymorphic: true
belongs_to :in_relation_to, polymorphic: true
end
end
So, in your User model, you would say something like:
class User < ActiveRecord::Base
has_many :owned_relationships,
as: :owner,
class_name: "ActsAsRelatingTo::Relationship",
dependent: :destroy
has_many :organizations_i_relate_to,
through: :owned_relationships,
source: :in_relation_to,
source_type: "Organization"
...
end
I believe you may be able to leave the source_type argument off since the joined class (Organization) can be inferred from :organizations. Often, I'm joining models where the class name cannot be inferred from the relationship name, in which case I include the source_type argument.
With this, you can say user.organizations_i_relate_to. You can do the same set up for a relationship between any set of classes.
You could also say in your Organization class:
class Organization < ActiveRecord::Base
has_many :referencing_relationships,
as: :in_relation_to,
class_name: "ActsAsRelatingTo::Relationship",
dependent: :destroy
has_many :users_that_relate_to_me,
through: :referencing_relationships,
source: :owner,
source_type: "User"
So that you could say organization.users_that_relate_to_me.
I got tired of having to do all the set up, so in my gem I created an acts_as_relating_to method so I can do something like:
class User < ActiveRecord::Base
acts_as_relating_to :organizations, :teams
...
end
and
class Organization < ActiveRecord::Base
acts_as_relating_to :users, :organizations
...
end
and
class Team < ActiveRecord::Base
acts_as_relating_to :organizations, :users
...
end
and all the polymorphic associations and methods get set up for me "automatically".
Sorry for the long answer. Hope you find something useful in it.
I'm actually trying to create a has_many through association. Let me first explain a bit about how things are supposed to work.
I have a users, groups and members tables. The rules are as follow :
A user can create a group (depending on it's role) (groups table has a user_id)
A user can be member of one or many groups (members table contain user_id and group_id)
Here is my current relationship classes :
class User < ActiveRecord::Base
# Associations
has_many :groups # As user, I create many groups
has_many :members
has_many :groups, through: :members # But I can also belongs to many groups
end
class Group < ActiveRecord::Base
# Associations
belongs_to :user
has_many :members
has_many :users, through: :members
end
class Member < ActiveRecord::Base
# Associations
belongs_to :user
belongs_to :group
end
My problem is about the group relationship. You see a user can create groups, which means :
has_many :groups
but a user can also be member of groups :
has_many :groups, through: :members
Because of this new relationship, 75% of my specs are now broken. Also, I notice that if I logged in with a user associated to a group, I can see actually groups list. But when I'm trying to logged in as group owner (the one who created the group), I can not see the groups created by that user).
Idea?
You are not looking for an has_many through relationship here
Try that :
class User < ActiveRecord::Base
# Associations
has_and_belongs_to_many :groups
has_many :created_groups, class_name: 'Group', foreign_key: 'creator_id'
end
class Group < ActiveRecord::Base
# Associations
belongs_to :creator, class_name: 'User'
has_and_belongs_to_many :members, class_name: 'User'
end
This is a solution if you don't need the member class to do any special treatment.
You should have a migration that looks like that:
class CreateGroupsUsers < ActiveRecord::Migration
def change
create_table :groups_users, id: false do |t|
t.references :group
t.references :user
end
add_index :groups_users, [:group_id, :user_id]
add_index :groups_users, :user_id
end
end
And you have to make sure that your groups table have a creator_id !