我有两个带有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中的错误吗?
感谢您提供帮助。
答案 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