为什么通过belongs_to的关联对象不等于自己?

时间:2009-09-23 19:45:51

标签: ruby-on-rails activerecord

我有两个带有has_many和belongs_to关联的类:

class Employee < ActiveRecord::Base
  has_many :contracts
end
class Contract < ActiveRecord::Base
  belongs_to :employee
end

我希望Contract类的#employee方法返回的员工与自己相等,这意味着下面的单元测试会通过。

class EmployeeTest < ActiveSupport::TestCase
  test "an object retrieved via a belongs_to association should be equal to itself" do
    e = Employee.new
    e.contracts << Contract.new
    assert e.save
    a = e.contracts[0].employee
    assert a.equal? a
  end
end

然而,它失败了。我不明白。这是ActiveRecord中的错误吗?

感谢您提供帮助。

2 个答案:

答案 0 :(得分:3)

这与对象相等有关。考虑这个IRB会议

irb(main):010:0> Foo = Class.new
=> Foo
irb(main):011:0> f = Foo.new
=> #<Foo:0x16c128>
irb(main):012:0> b = Foo.new
=> #<Foo:0x1866a8>
irb(main):013:0> f == b
=> false

默认情况下,==将测试两个对象具有相同的类型和相同的object_id。在activerecord中,它正在为第一个员工打开数据库,并通过参考方法再次为员工点击它,但这些是两个不同的对象。由于object_ids是不同的,如果它们具有所有相同的值并不重要,==将返回false。要更改此行为,请考虑第二个IRB会话

irb(main):050:0> class Bar
irb(main):051:1> attr_accessor :id
irb(main):052:1> def ==(compare)
irb(main):053:2> compare.respond_to?(:id) && @id == compare.id
irb(main):054:2> end
irb(main):055:1> end
=> nil
irb(main):056:0> a = Bar.new
=> #<Bar:0x45c8b50>
irb(main):057:0> b = Bar.new
=> #<Bar:0x45c2430>
irb(main):058:0> a.id = 1
=> 1
irb(main):059:0> b.id = 1
=> 1
irb(main):060:0> a == b
=> true
irb(main):061:0> a.id = 2
=> 2
irb(main):062:0> a == b
=> false

这里我定义了==运算符来比较两个对象上的.id方法(如果我们比较的对象没有id方法,则返回false)。如果您想按照这样的值比较Employees,您将必须定义自己的==方法来实现它。

答案 1 :(得分:0)

这可能是因为两个关联调用中的rails内部缓存不同。尝试做

  a.reload.equal? a.reload 

这将摆脱缓存并应该返回true