ActiveRecord多态关联

时间:2017-09-10 10:00:25

标签: ruby-on-rails ruby database postgresql activerecord

我有一个允许用户与其他用户进行对话的项目。 对话可以通过UserConversations模式包含多个用户。 UserConversations需要具有多态性,以便它们也属于Chatrooms。但是,当我添加多态关联时,我的关系会破裂。

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: "loi@coderschool.vn", 
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

我正在使用Rails 5.1.3&amp; ruby 2.3.1

我需要user.conversations才能工作。请帮忙!

3 个答案:

答案 0 :(得分:1)

使用两个连接模型,它既简单又避免了多态的主要缺点:

  • 没有外键支持,因为DB不知道关联指向哪个表。
  • 联接很棘手,因为您必须查询表以了解要加入的表。这对连接表来说真的很糟糕。

由于连接表只包含两列,并且模型使用多态性的逻辑非常少,因此除了令人头疼之外并没有给你带来任何好处。

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

答案 1 :(得分:0)

根据使用 has_many到http://guides.rubyonrails.org/association_basics.html#the-has-many-through-association)的rails文档,如果我们认为UserConversation是用户和对话之间的中间表,它应该是这样的:

class User < ApplicationRecord
  has_many :user_conversations
  has_many :conversations, through: :user_conversations 
end

class UserConversation < ApplicationRecord
  belongs_to :user
  belongs_to :conversation
end

class Conversation < ApplicationRecord
  has_many :user_conversations
  has_many :users, through: :user_conversations
end

完成其余的关系并再次:dependent

答案 2 :(得分:0)

这就是我得到的结果(寻找用户对话)。它并不像我想的那样优雅,但我认为它有用。

# user.rb

def conversations
  Conversation.where(id: user_conversations.where(parent_type: 
  "Conversation").map(&:parent_id))
end