为什么object_a!= object_b,如果它们具有完全相同的id,类型和属性?

时间:2011-11-24 16:51:09

标签: ruby-on-rails ruby activerecord equals comparison-operators

我有两个User对象应该是相同的,但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

6 个答案:

答案 0 :(得分: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

答案 1 :(得分:0)

我不知道这些是什么类型的物体。从Object开始,他们是否合适?

除非您覆盖Object#==并定义更合适的行为,否则

Object#===确实只是#==。要使Object#== =为真,它们必须实际上是对同一对象的引用,而不是对等对象。

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

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

答案 2 :(得分:0)

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

我建议您在id上比较它们。

答案 3 :(得分:0)

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

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

答案 4 :(得分: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

答案 5 :(得分:-2)

逻辑解释:

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

如果一个物体就像另一个物体,它不一定相同。

技术说明:

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

如果您有对象A和对象。

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

a = current_user  
b = a
a== b
true

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