1

我有两个应该相同的用户对象,但 ruby​​ 说它们不是。谁能向我解释这里发生了什么?

a = current_user  
b = votable.user

a == b  
false   
a.id == b.id  
true  
a.name == b.name  
true  
a.attributes == b.attributes  
true

自原始发布以来的更新/附加信息:

  • 原来我遇到的问题是间歇性的。它发生在我刷新相关页面的时间的 30% 左右。70% 的时间,A == B,一切都按预期工作。但在 30% 的情况下,A 不等于 B。
  • 当问题发生时,Ruby 实际上告诉我我的对象的类(类型)不一样,即使它们看起来相同(用户和用户)。这是问题发生时 30% 的输出:

.

a.class == b.class AKA a.type == b.type
false (note: this is a correction to the original post which said true)
a.class.to_s
"User"
b.class.to_s
"User"
a.class.name == b.class.name
true
a.class.methods == b.class.methods
true
a.class.object_id == b.class.object_id
false

所以对象的类(类型)看起来完全一样。据说是用户。但是当你评估 a.class == b.class 时,在我渲染页面的 30% 的时间里,答案是错误的,从而导致了问题。

谁能告诉我发生了什么事?非常感谢。

➜ ~ ruby​​ --version
ruby​​ 1.8.7 (2010-01-10 patchlevel 249) [universal-darwin11.0]
➜ ~ rails --version
Rails 3.0.10

4

6 回答 6

3

如果a == b是假的,那么我猜它正在做类似的事情a.object_id == b.object_id,只有当引用指向同一个对象时才会正确。

a.id == b.id可能只是检查User.id并且它是真的是有道理的。

最简单的事情就是继续检查User.id。如果您真的想使用==,则需要在 User 类中使用以下内容覆盖它:

class User
  def ==(other)
    self.id == other.id
  end
end
于 2011-11-24T16:58:04.970 回答
0

我不知道这些是什么物品。他们只是体面Object吗?

Object#==Object#===除非您覆盖#==并定义更合适的行为,否则确实会这样做。要使Object#=== 为真,它们实际上必须是对 SAME OBJECT 的引用,而不是对等对象的引用。

只需定义一个#==方法并使用一些理智的逻辑来确定两个对象是否相同......然后你可以使用a == b和 get true

如果这些是ActiveRecord::Base后代,那么就会发生其他事情,因为ActiveRecord::Base对象确实有一个理智的#==方法(尽管您也可以覆盖该行为)。

于 2011-11-24T16:57:39.680 回答
0

这两个对象不是同一个对象。但是,它们引用数据库中的同一用户。

我建议你id像你一样比较它们。

于 2011-11-24T16:57:46.257 回答
0

如果您使用的是 Rails 3,并假设上面的每个方法都返回一个 ActiveRelation(或至少其中一个返回)。那么可以肯定地说第一个比较是正确的,因为每个 ActiveRelation 可能是一个不同的对象。

我的回答对您的代码做了一些假设,但可能有助于提供一些见解。

于 2011-11-24T17:28:10.310 回答
0

根据http://api.rubyonrails.org/classes/ActiveRecord/Base.html#method-i-3D-3D上的 Rails 文档,相等运算符应该检查类型和 id。

# File activerecord/lib/active_record/base.rb, line 1811
def ==(comparison_object)
  super ||
    comparison_object.instance_of?(self.class) &&
    id.present? &&
    comparison_object.id == id
end

必须发生的是,它们不是同一类。你能检查并输出结果吗?

votable.user.class
current_user.class
于 2011-11-24T17:41:19.647 回答
-2

逻辑解释:

它们具有相似的属性,但本质上是不同的。请注意,地球和火星是不同的行星,即使我们只看它们都在银河系中并且都是行星的事实。

如果一个对象与另一个对象相似,则不一定相同。

技术说明:

创建对象时,将创建对该对象的引用。如果您创建另一个对象,将创建另一个引用。

如果你有对象 A 和对象。

a = current_user  
b = votable.user
a == b
false

a = current_user  
b = a
a== b
true

如果两个对象的引用相同(当然它们的属性也相同),则它们是相等的。如果标准关系不够,您总是可以编写方法来定义新的等价关系;)

于 2011-11-24T17:21:19.987 回答