Имеет ли смысл переопределять метод '==' в подклассах ActiveRecord? - PullRequest
2 голосов
/ 24 июня 2009

Класс Rails ActiveRecord::Base определяет метод ==, который возвращает true, если объекты идентичны или имеют одинаковый идентификатор.

Я переопределил == в нескольких моих моделях Rails, чтобы учесть более значимые условия равенства. Они работают, когда я сравниваю объекты напрямую (например, через script/console), но если я делаю что-то вроде my_array_of_models.include? other_model, include? всегда возвращает false. даже если массив содержит «равный» объект (согласно моему определению).

Я исправил это, выполнив, например, my_array_of_models.any? { |el| el.attr == other_model.attr } (в любом случае, мне кажется, что вам рекомендуется проводить сравнения), но мне интересно: имеет ли смысл переопределять == в ActiveRecord моделирует или ActiveRecord делает что-то на высоком уровне, что делает такой переопределенный метод бесполезным (или, что еще хуже, опасным)?

Источник

Вот мои реализации моих переопределенных методов. Есть два класса, User и Contact. Users имеют уникальные адреса электронной почты, поэтому == возвращает true, если адреса электронной почты совпадают. Contact является мостом между Users (как отношения "друг" в социальных сетях) и должен возвращать true, если они имеют одинаковые user_id.

class User < ActiveRecord::Base
  def ==(other)
    other.respond_to?(:email) and self.email == other.email
  end
end

class Contact < ActiveRecord::Base
  def ==(other)
    if other.class == self.class
      self.user == other.user
    elsif other.kind_of? User
      self.user == other
    else
      false
    end
  end
end

Как я уже отметил, он работает при прямом сравнении (например, one_object == another_object), но my_array_of_objs.include? included_obj всегда возвращает false.

Ответы [ 3 ]

0 голосов
/ 21 июля 2009

Еще один способ сформулировать ваш вопрос: «метод == считается« окончательным »?». В Java вы можете использовать ключевое слово final, чтобы предотвратить переопределение метода в подклассах (вы также можете применить final к классам, чтобы они вообще не могли быть разделены на подклассы). Это может быть удобно при проектировании ОО, поскольку некоторые классы или методы не предназначены для переопределения. В Ruby, конечно, нет «final», но, возможно, здесь применима та же концепция (возможно, вы даже сможете реализовать ее с помощью метапрограммирования).

Я помню, как читал несколько хороших статей и / или SO сообщений об использовании 'final' в OO. Я отредактирую их, если найду.

0 голосов
/ 02 марта 2018

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

Как отметил Хемант Кумар, вы можете переопределить его, но при этом объекты с разными идентификаторами, но одинаковыми атрибутами считаются равными, что не соответствует действительности.

Также с этим изменением дизайн переходит от объекта сущности ActiveRecord к объекту чистого значения.

Возможное решение вашей проблемы:

Rails сознательно делегирует проверки на равенство в столбец идентификаторов. Если вы хотите узнать, содержат ли два объекта AR один и тот же материал, сравните результат вызова #attributes для обоих.

https://stackoverflow.com/a/4738485/2987689

Этот вопрос также имеет другой хороший подход (https://stackoverflow.com/a/7098377/2987689)

0 голосов
/ 24 июня 2009

Возможно, поучительно прочитать эту часть документации:

http://ruby -doc.org / ядро ​​/ классов / object.html # M000341

array_of_models.include?(my_object) возможно, не работает, потому что == не используется для проверки наличия объекта в коллекции. Используется equal?.

EDIT

Утверждение ОП о том, что даже когда он переопределяет метод == для своих моделей, array.include?(obj) возвращает false, не соответствует действительности. Давайте посмотрим на это:

class Event < ActiveRecord::Base
  def ==(that)
    if(that.eventname == self.eventname)
      true
    else
      false
   end
 end
end
>> a << Event.find(1)
=> [#<Event id: 1, eventname: "hemant", foo: nil, created_at: "2009-06-24 21:33:00", updated_at: "2009-06-24 21:33:00">]

>> b = Event.find(2)
=> #<Event id: 2, eventname: "hemant", foo: nil, created_at: "2009-06-24 21:33:04", updated_at: "2009-06-24 21:33:04">

>> a.include?(b)
=> true

Очевидно, это не правда. Но в любом случае, я думаю, так как AR определяет == определенным образом, не стоит переопределять его. Это может привести к трудностям при обнаружении ошибок.

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