Ruby on Rails - ActiveRecord ::关系计数方法有误吗?

Ada*_*ite 4 ruby activerecord rspec ruby-on-rails mailboxer

我正在编写一个应用程序,允许用户发送有关"优惠"的消息.

我以为我会节省一些工作并使用Mailboxer宝石.

我正在遵循RSpec的测试驱动开发方法.我正在编写一个测试,确保Conversation每个优惠只允许一个.提供belongs_to两个不同的用户(提出要约的用户和收到要约的用户).

这是我的失败测试:

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
Run Code Online (Sandbox Code Playgroud)

因此,在测试运行之前,用户会sending_user向receiving_user发送两次消息.该message_user_regarding_offer!如下所示:

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
Run Code Online (Sandbox Code Playgroud)

在测试的第一次迭代中(当发送第一条消息时),conversation变量nil因此发送消息并在两个用户之间创建对话.

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

这一切都有效,但测试失败了,我无法理解为什么!

当我在上面指定的位置的代码中放置一个pry绑定时,我可以检查发生了什么...现在谜语我:

wtf红宝石

self.mailbox.conversations[0]返回一个Conversation实例

self.mailbox.conversations[1] 回报 nil

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

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

那里发生了什么?该count方法不正确,我的测试失败...

我错过了什么?或者这是一个错误?!

编辑

offer.conversation 看起来像这样:

  def conversation
    Conversation.where({subject: conversation_subject}).last
  end
Run Code Online (Sandbox Code Playgroud)

并且offer.conversation_subject:

  def conversation_subject
    "offer-#{self.id}"
  end
Run Code Online (Sandbox Code Playgroud)

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

wtf红宝石2

也...

Conversation.all.count 返回1!

和:

Conversation.all == self.mailbox.conversations 回报 true

Conversation.all.count == self.mailbox.conversations.count 回报 false

如果阵列相等,怎么会这样?我不知道这里发生了什么,现在已经开始了.认为这是一个错误?!

编辑3

从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
Run Code Online (Sandbox Code Playgroud)

reply_to_convesation代码可以在这里- > http://rubydoc.info/gems/mailboxer/frames.

只是看不出我做错了什么!可能会修改我的测试以解决这个问题.或抛弃宝石并写下我自己的宝石.

tih*_*hom 9

看到这个Rails 3:Relation.count和Relation.all.count之间的区别

简而言之,select当您将count应用于查询时,Rails会忽略列(如果不止一个).这是因为

SQL的COUNT只允许一列或更少的列作为参数.

Mailbox 代码

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

self.mailbox.conversations.count忽略select('DISTINCT conversations.*')和计数joinreceipts,基本上是计数的数量receipts与重复conversations它.

另一方面,self.mailbox.conversations.all.count首先获取应用the的记录select,该记录是唯一的conversations,然后对其进行计数.

self.mailbox.conversations.all == self.mailbox.conversations 因为他们都用select查询db.

要解决您的问题,您可以使用sending_user.mailbox.conversations.all.countsending_user.mailbox.conversations.group('conversations.id').length