Rails:列表Conversation.users,如果多个user_ids存储在多个列

Rails: list Conversation.users, if multiple user_ids stored in multiple columns

如果与 Conversations 关联的所有用户存储在不同的列中,我如何列出所有这些用户。

即,对于下面的示例,我如何调用 c.users 并获得 [#<User id: 1>, #<User id: 2>]

Class:

class Conversation < ApplicationRecord
  belongs_to :user, foreign_key: :initiator_id
  belongs_to :user, foreign_key: :recipient_id
end

正在测试:

>> c = Conversation.first
>> c.initiator_id
=> 1
>> c.recipient_id
=> 2
>> c.user
=> #<User id: 2> # This only lists one user
> c.users
NoMethodError: undefined method `users'

一个解决方案是创建一个子查询

SELECT 
conversations.id AS conversation_id,
initiator_id AS user_id
UNION
SELECT 
conversations.id AS conversation_id,
recipient_id AS user_id

这将直接为您提供用户和对话之间的关系。如果您经常这样做,您可以将其创建为视图,以便您可以直接在 Activerecord 中查询此 table。

整个查询是

SELECT conversations_users.user_id
FROM 
  (SELECT 
  conversations.id AS conversation_id,
  initiator_id AS user_id
  UNION
  SELECT 
  conversations.id AS conversation_id,
  recipient_id AS user_id) conversations_users
WHERE conversations_users.conversation_id IN ?

在哪里使用具有适当值的 conversation_id。 如果您经常这样做,那么 运行 迁移以将其创建为视图是有意义的。 高清

  ActiveRecord::Base.connection.execute <<-SQL
CREATE OR REPLACE VIEW conversations_users_view AS
    SELECT 
conversations.id AS conversation_id,
initiator_id AS user_id
UNION
SELECT 
conversations.id AS conversation_id,
recipient_id AS user_id
SQL
end

然后你创建一个conversations_users活动记录模型

class ConversationsUser < ActiveRecord::Base
  self.table_name = 'conversations_users_view'
end

那你就可以直接查询了

users = ConversationsUser.where('conversations_id IN ?', c.id)

创建两个关联并像这样使用它们:

class Conversation < ApplicationRecord
  belongs_to :initiator, foreign_key: :initiator_id, class_name: 'User'
  belongs_to :recipient, foreign_key: :recipient_id, class_name: 'User'

  def users
    [initiator, recipient]
  end
end

不确定这是否是一个好方法,但你可以实现你想要的