Почему object_a! = Object_b, если они имеют одинаковый идентификатор, тип и атрибуты? - PullRequest
1 голос
/ 24 ноября 2011

У меня есть два объекта 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
Рельсы 3.0.10

Ответы [ 6 ]

3 голосов
/ 24 ноября 2011

Если 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
0 голосов
/ 24 ноября 2011

Согласно документации Rails на http://api.rubyonrails.org/classes/ActiveRecord/Base.html#method-i-3D-3D, оператор равенства должен проверять тип и идентификатор.

# 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
0 голосов
/ 24 ноября 2011

Если вы используете Rails 3 и предполагаете, что каждый из указанных выше методов возвращает ActiveRelation (или, как минимум, один из них).Тогда можно было бы с уверенностью сказать, что первое сравнение является правильным, поскольку каждая ActiveRelation, вероятно, является отдельным объектом.

Мой ответ делает несколько предположений о вашем коде, но может помочь предложить некоторую информацию.

0 голосов
/ 24 ноября 2011

Логическое объяснение:

У них есть схожие свойства, но они существенно различаются. Обратите внимание, что Земля и Март - это разные планеты, даже если мы только посмотрим на факты, которые оба находятся в галактике Млечный Путь, и обе они являются планетами.

Если объект похож на другой объект, он не обязательно совпадает.

Техническое объяснение:

При создании объекта будет создана ссылка на объект. Если вы создадите другой объект, будет создана другая ссылка.

Если у вас есть объект А и объект.

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

a = current_user  
b = a
a== b
true

Два объекта равны, если их ссылка одинакова (и их атрибуты тоже, конечно, одинаковы). Вы всегда можете написать методы для определения новых отношений эквивалентности, если стандартных отношений недостаточно;)

0 голосов
/ 24 ноября 2011

Два объекта не являются одним и тем же объектом. Однако они ссылаются на одного и того же пользователя в базе данных.

Предлагаю вам сравнить их на id, как вы это сделали.

0 голосов
/ 24 ноября 2011

Я не знаю, что это за объекты.Они просто приличные от Object?

Object#== на самом деле просто делают Object#===, если вы не переопределите #== и не определите более подходящее поведение.Чтобы Object#== = было истинно, они должны быть ссылками на ОДИН И ТОЖЕ ОБЪЕКТ, а не эквивалентными объектами.

Просто определите метод #== и используйте некоторую разумную логику, чтобы определить, совпадают ли два объекта... тогда вы можете использовать a == b и получить true.

Если это ActiveRecord::Base потомки, тогда происходит что-то еще, так как ActiveRecord::Base объекты имеют вменяемый метод #== (хотяВы также можете переписать это поведение).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...