问题描述
我正在编写一个应用程序,允许用户相互发送关于报价"的消息.
我想我可以节省一些工作并使用 .
就是看不出我做错了什么!可能会重做我的测试来解决这个问题.或者放弃 gem 并编写我自己的.
见这个 Rails 3:Relation.count 和 Relation.all.count 之间的区别
简而言之,当您将 count 应用于查询时,Rails 会忽略 select
列(如果有多个).这是因为
SQL 的 COUNT 只允许一列或更少列作为参数.
来自 Mailbox
代码
作用域 :participant, lambda {|participant|选择('不同的对话.*').where('notifications.type'=> Message.name).订单(conversations.updated_at DESC").joins(:receipts).merge(Receipt.recipient(participant))}
self.mailbox.conversations.count
忽略 select('DISTINCT对话.*')
并用 计算
,实质上是计算其中包含重复 join
表>receiptsconversations
的 receipts
的数量.
另一方面,self.mailbox.conversations.all.count
首先获取应用 select
的记录,它得到唯一的 conversations
然后数数.
self.mailbox.conversations.all == self.mailbox.conversations
因为他们都使用 select 查询数据库.
要解决您的问题,您可以使用 sending_user.mailbox.conversations.all.count
或 sending_user.mailbox.conversations.group('conversations.id').length
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::Relation count 方法错误?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!