Reputation: 2137
I have a project that allows users to have conversations with other users.
Conversations can contain multiple users via a UserConversations
modal.
UserConversations
need to be polymorphic so that they can also belong to Chatrooms
. However, when I add the polymorphic association my relationships break.
class User < ApplicationRecord
has_many :user_conversations, dependent: :destroy
has_many :conversations, through: :user_conversations
end
class UserConversation < ApplicationRecord
belongs_to :user
belongs_to :parent, polymorphic: true
has_many :conversations, through: :user_conversations
end
class Conversation < ApplicationRecord
has_many :messages, as: :context, dependent: :destroy
has_many :user_conversations, as: :parent, dependent: :destroy
has_many :users, through: :user_conversations
end
class Chatroom < ApplicationRecord
belongs_to :venue
has_many :messages, as: :context, dependent: :destroy
has_many :user_conversations, as: :parent, dependent: :destroy
has_many :users, through: :user_conversations
end
2.3.1 :009 > user = User.first
User Load (1.8ms) SELECT "users".* FROM "users" ORDER BY "users"."id" ASC
LIMIT $1 [["LIMIT", 1]]
=> #<User id: 1, name: "Loi Tran", email: "[email protected]",
password_digest: "$2a$10$eDZ6IyTAzVK4qNvJfIhPP.3fhEIhdv0bWuVqrTjJk86...",
image_url: "https://scontent.fsgn5-2.fna.fbcdn.net/v/t1.0-1/p3...",
created_at: "2017-08-21 07:20:11", updated_at: "2017-08-29 18:47:04", city:
"Tallahassee", state: "Florida", position: "Getting yelled at", school:
"Florida State University", quote: "If it was easy, everyone would do it.",
avatar: nil, last_name: "Tran", first_name: "Loi">
2.3.1 :010 > user.user_conversations
UserConversation Load (0.8ms) SELECT "user_conversations".* FROM
"user_conversations" WHERE "user_conversations"."user_id" = $1 LIMIT $2
[["user_id", 1], ["LIMIT", 11]]
=> #<ActiveRecord::Associations::CollectionProxy [#<UserConversation id: 453, user_id: 1, created_at: "2017-09-10 06:01:27", updated_at: "2017-09-10 06:01:27", parent_type: "Chatroom", parent_id: 8>, #<UserConversation id: 454, user_id: 1, created_at: "2017-09-10 06:02:22", updated_at: "2017-09-10 06:02:22", parent_type: "Conversation", parent_id: 318>]>
2.3.1 :011 > user.conversations
NoMethodError: undefined method `klass' for nil:NilClass
Did you mean? class
from (irb):11
I'm using Rails 5.1.3
& ruby 2.3.1
I need user.conversations to work. Please help!
Upvotes: 0
Views: 917
Reputation: 102016
Use two join models instead, its both simpler and will avoid the major cons of polymorphism:
Since join tables just consist of two columns and the model has very little logic using polymorphism does not really give you anything but headaches.
class User < ApplicationRecord
has_many :user_conversations, dependent: :destroy
has_many :conversations, through: :user_conversations
has_many :chatroom_users, dependent: :destroy
has_many :chatrooms, through: :chatroom_users
end
class UserConversation < ApplicationRecord
belongs_to :user
belongs_to :conversation
end
class Conversation < ApplicationRecord
has_many :messages, as: :context, dependent: :destroy
has_many :user_conversations, dependent: :destroy
has_many :users, through: :user_conversations
end
class ChatroomUser < ApplicationRecord
belongs_to :user
belongs_to :chatroom
end
class Chatroom < ApplicationRecord
belongs_to :venue
has_many :messages, as: :context, dependent: :destroy
has_many :chatroom_users, dependent: :destroy
has_many :users, through: :user_chatrooms
end
Upvotes: 1
Reputation: 2137
This is how I got the result I was looking for(finding a users conversations). It's not as elegant as I would like but I think it serves the purpose.
# user.rb
def conversations
Conversation.where(id: user_conversations.where(parent_type:
"Conversation").map(&:parent_id))
end
Upvotes: 0
Reputation: 584
According to rails documentation when using has_many through (http://guides.rubyonrails.org/association_basics.html#the-has-many-through-association), if we consider UserConversation is the middle table between User and conversations, it should be something like this:
class User < ApplicationRecord
has_many :user_conversations
has_many :conversations, through: :user_conversations
end
and
class UserConversation < ApplicationRecord
belongs_to :user
belongs_to :conversation
end
and
class Conversation < ApplicationRecord
has_many :user_conversations
has_many :users, through: :user_conversations
end
Put the rest of your relations and :dependent
again.
Upvotes: 0