本文介绍了Ruby on Rails的 - 的ActiveRecord ::关系计数法是错误的?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在写一个应用程序,允许用户发送一个关于一个'报价'的另一个消息。

我想我会拯救自己的一些工作,并使用 Mailboxer 的宝石。

我在与RSpec的测试驱动的开发方法。我正在写一个测试,应确保只有一个会话元的报价是允许的。 belongs_to的要约两个不同的用户(即提出收购用户,并且所收到的报价的用户)。

下面是我失败的测试:

 说明后,消息被发送到同一个用户两次吗
  之前做
    2.times {sending_user.message_user_regarding_offer!报价,receiving_user,random_string}
  结束
  指定{sending_user.mailbox.conversations.count.should == 1}
结束
 

所以测试运行用户之前 sending_user 将消息发送到receiving_user的两倍。 !本 message_user_regarding_offer 是这样的:

 高清message_user_regarding_offer!报价,接收器,体
    谈话= offer.conversation
    如果conversation.nil?
      self.send_message(接收机,身体,offer.conversation_subject)
    其他
      self.reply_to_conversation(谈话,体)
      #我把binding.pry这里查看控制台
    结束
    offer.create_activity键:PublicActivityKeys.message_received,老板:自我,收件人:接收器
结束
 

在测试中的第一次迭代(当第一条消息被发送)的会话变量因此,一个消息发送和两个用户之间建立一个对​​话。

在第二次迭代中的第一次迭代中创建的会话返回并且用户答复该谈话,但不创建一个新的对话。

这一切工作,但测试失败,我不明白为什么!

当我把撬在code上面我指定的可以检查是怎么回事的位置绑定...现在谜语我:

self.mailbox.conversations [0] 返回会话实例

self.mailbox.conversations [1] 返回

self.mailbox.conversations 清楚地显示了包含一个对象的集合。

self.mailbox.conversations.count 返回2?!

这是怎么回事呢?在计数方法是不正确的,我的测试失败......

我在想什么?或者这是一个错误?!

修改

offer.conversation 是这样的:

 高清通话
    Conversation.where({主题:conversation_subject})。最后
  结束
 

offer.conversation_subject

 高清conversation_subject
    报价 - #{self.id}
  结束
 

编辑2 - 显示在第一和第二次迭​​代撬

另外...

Conversation.all.count 返回1​​!

Conversation.all == self.mailbox.conversations 返回

Conversation.all.count == self.mailbox.conversations.count 返回

这怎么可能,如果数组是一样的吗?我不知道现在发生了什么事情就到这里,吹小时这一点。认为这是一个错误?!

修改3

从Mailboxer宝石的来源......

 高清通话(选项= {})
  CONV = Conversation.participant(@messageable)

  如果选项[:mailbox_type]。present?
    案例选项[:mailbox_type]
    当收件箱
      CONV = Conversation.inbox(@messageable)
    当发件箱
      CONV = Conversation.sentbox(@messageable)
    当垃圾
      CONV = Conversation.trash(@messageable)
    当not_trash
      CONV = Conversation.not_trash(@messageable)
    结束
  结束

  如果(options.has_key(:读取)及和放大器;选项?[:阅读] ==假)|| (options.has_key(:未读)及和放大器;选项?[:未读] ==真)
    CONV = conv.unread(@messageable)
  结束

  CONV
结束
 

reply_to_convesation code是可以在这里 - >的。

只是不明白我在做什么错了!可能返工我的测试来解决这个问题。或者沟宝石,写我自己的。

解决方案

看到这样的Rails 3:Relation.count和Relation.all.count 的区别

在短暂的Rails忽略选择列(如果有多个),当你申请数量的查询。这是因为

邮箱

 范围:参加者的lambda {|参与者|
    选择(DISTINCT对话。*)。
      其中,('notifications.type'=> Message.name)。
      为了(conversations.updated_at DESC)。
      加入(:收益).merge(Receipt.recipient(参与者))
  }
 

self.mailbox.conversations.count 忽略选择(DISTINCT对话。*')和计数加入收入收益基本计算数与复制它对话

在另一方面, self.mailbox.conversations.all.count 首先获得应用记录的选择 ,其中获得独特的对话然后计算它。

self.mailbox.conversations.all == self.mailbox.conversations ,因为他们两人查询与选择的分贝。

要解决你的问题,你可以使用 sending_user.mailbox.conversations.all.count sending_user.mailbox.conversations.group(对话。 ID)。长度

I'm writing an application that allows users to send one another messages about an 'offer'.

I thought I'd save myself some work and use the Mailboxer gem.

I'm following a test driven development approach with RSpec. I'm writing a test that should ensure that only one Conversation is allowed per offer. An offer belongs_to two different users (the user that made the offer, and the user that received the offer).

Here is my failing test:

describe "after a message is sent to the same user twice" do
  before do 
    2.times { sending_user.message_user_regarding_offer!  offer, receiving_user, random_string }
  end
  specify { sending_user.mailbox.conversations.count.should == 1 }
end

So before the test runs a user sending_user sends a message to the receiving_user twice. The message_user_regarding_offer! looks like this:

def message_user_regarding_offer! offer, receiver, body
    conversation = offer.conversation
    if conversation.nil?
      self.send_message(receiver, body, offer.conversation_subject)
    else  
      self.reply_to_conversation(conversation, body)
      # I put a binding.pry here to examine in console
    end
    offer.create_activity key: PublicActivityKeys.message_received, owner: self, recipient: receiver
end

On the first iteration in the test (when the first message is sent) the conversation variable is nil therefore a message is sent and a conversation is created between the two users.

On the second iteration the conversation created in the first iteration is returned and the user replies to that conversation, but a new conversation isn't created.

This all works, but the test fails and I cannot understand why!

When I place a pry binding in the code in the location specified above I can examine what is going on... now riddle me this:

self.mailbox.conversations[0] returns a Conversation instance

self.mailbox.conversations[1] returns nil

self.mailbox.conversations clearly shows a collection containing ONE object.

self.mailbox.conversations.count returns 2?!

What is going on there? the count method is incorrect and my test is failing...

What am I missing? Or is this a bug?!

EDIT

offer.conversation looks like this:

  def conversation
    Conversation.where({subject: conversation_subject}).last
  end

and offer.conversation_subject:

  def conversation_subject
    "offer-#{self.id}"
  end

EDIT 2 - Showing the first and second iteration in pry

Also...

Conversation.all.count returns 1!

and:

Conversation.all == self.mailbox.conversations returns true

and

Conversation.all.count == self.mailbox.conversations.count returns false

How can that be if the arrays are equal? I don't know what's going on here, blown hours on this now. Think it's a bug?!

EDIT 3

From the source of the Mailboxer gem...

def conversations(options = {})
  conv = Conversation.participant(@messageable)

  if options[:mailbox_type].present?
    case options[:mailbox_type]
    when 'inbox'
      conv = Conversation.inbox(@messageable)
    when 'sentbox'
      conv = Conversation.sentbox(@messageable)
    when 'trash'
      conv = Conversation.trash(@messageable)
    when  'not_trash'
      conv = Conversation.not_trash(@messageable)
    end
  end

  if (options.has_key?(:read) && options[:read]==false) || (options.has_key?(:unread) && options[:unread]==true)
    conv = conv.unread(@messageable)
  end

  conv
end

The reply_to_convesation code is available here -> http://rubydoc.info/gems/mailboxer/frames.

Just can't see what I'm doing wrong! Might rework my tests to get around this. Or ditch the gem and write my own.

解决方案

see this Rails 3: Difference between Relation.count and Relation.all.count

In short Rails ignores the select columns (if more than one) when you apply count to the query. This is because

From Mailbox code

 scope :participant, lambda {|participant|
    select('DISTINCT conversations.*').
      where('notifications.type'=> Message.name).
      order("conversations.updated_at DESC").
      joins(:receipts).merge(Receipt.recipient(participant))
  }

self.mailbox.conversations.count ignores the select('DISTINCT conversations.*') and counts the join table with receipts, essentially counting number of receipts with duplicate conversations in it.

On the other hand, self.mailbox.conversations.all.count first gets the records applying the select, which gets unique conversations and then counts it.

self.mailbox.conversations.all == self.mailbox.conversations since both of them query the db with the select.

To solve your problem you can use sending_user.mailbox.conversations.all.count or sending_user.mailbox.conversations.group('conversations.id').length

这篇关于Ruby on Rails的 - 的ActiveRecord ::关系计数法是错误的?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-26 11:16