1

用例

我有 3 个模型:

  • 一个Message
  • 一个Conversation
  • 一个MessageRecipient

关系定义为

  • A message has_and_belongs_to_many conversations(反之)
  • 一个message has_many message_recipients
  • A MessageRecipient belongs_toamessage和 a recipient(此处未定义)

它的工作原理

方法

@recipient.inbox_conversations.first.messages

创建以下 SQL 查询:

SELECT *
FROM `messages`
INNER JOIN `conversations_messages`
  ON `messages`.id = `conversations_messages`.message_id
WHERE (`conversations_messages`.conversation_id = 2061 ) 

结果是预期的消息:

[#<Message id: 7045, ..>]

问题

下一个方法(与上一个方法相同,具有额外的命名范围)

@recipient.inbox_conversations.first.messages.received_by(@recipient)

创建以下 SQL 查询:

SELECT * FROM `messages`
INNER JOIN `message_recipients`
  ON `message_recipients`.message_id = `messages`.id
INNER JOIN `conversations_messages`
  ON `conversations_messages`.message_id = `messages`.id
WHERE (`conversations_messages`.conversation_id = 2060 )
  AND (`message_recipients`.recipient_id = 32363)

它返回了一个不存在的ActiveRecord 元素

[#<Message id: 9025, ..>]

我试图Message.find_by_id(9025)在这一行之后做一个,这会返回nil

你想要一些额外的代码吗?

class Message

named_scope :received_by, lambda { |recipient| {
  :conditions => [ "`#{MessageRecipient.table_name}`.recipient_id = ?", recipient.id ],
  :joins => "INNER JOIN `#{MessageRecipient.table_name}`
   ON `#{MessageRecipient.table_name}`.message_id = `#{Message.table_name}`.id"
} }

.

class Receiver

def inbox_conversations
  inbox_messages = Message.received_by(self).find(:all, :include => :conversations)
  return inbox_messages.map(&:conversations).flatten.uniq
end

感谢您阅读本文!

4

1 回答 1

2

问题在于,当结果集中的 2 个或更多列具有相同的名称时,rails 2 并不是特别聪明:rails 只查看列名,因此它们会相互覆盖。在您的情况下,来自连接表之一的 id 正在隐藏消息表中的 id。

您需要在您的范围中添加一个选择选项,以仅从消息表 ( :select => 'messages.*') 中检索列,或者如果您确实需要连接表中的列,则仅选择您需要的列,并确保为任何冲突的列名设置别名。

于 2013-07-18T18:00:36.160 回答