2013-04-20 3 views
1

Вот мои модели:Rails inverse_of не работает с условиями

class Flight < ActiveRecord::Base 
    has_many :seats, dependent: :destroy, inverse_of: :flight 
end 

class Seat < ActiveRecord::Base 
    belongs_to :flight, inverse_of: :seats 
end 

кажется, что inverse_of работает хорошо, но когда я использую условие он не работает:

f1 = Flight.first 
s1 = f1.seats.first 
s2 = f1.seats.second 
s3 = f1.seats.where(id: 0..1000000).third 

s1.flight.equal? s2.flight 
=> true 
s1.flight.equal? s3.flight 
=> false 

Что объясняет это? Как я могу сделать эту работу?

ответ

0
s1.flight.equal? s2.flight 
=> true 

Вышеуказанные выходы так, потому что s1.flight и s2.flight относятся к точно такой же объект Рубин.

s1.flight.equal? s3.flight 

Здесь s1.flight и s3.flight относятся к различному Рубину объектов. Оба они содержат одни и те же данные записи (в том числе тот же :id значения)

Проблема заключается в том что вы используете метод equal? в Ruby, когда вы должны использовать == или eql? компараторов рельсов.

От the Ruby Object docs for ==(aliased as eql? and equal?)

Равенство - На уровне объекта, == возвращает истину, только если OBJ и другие такие же объект. Как правило, этот метод переопределяется в классах потомков, чтобы обеспечить значение, специфичное для класса.

К сожалению, equal? является изменением не переопределения в ActiveRecord::Base. От the Rails docs for ==(aliased as eql?):

Возвращает истину, если comparison_object является точно таким же объектом, или comparison_object того же типа и сам имеет идентификатор и оно равно comparison_object.id.

Вы найдете это не имеет отношения к :inverse_of. Простой пример, который вы можете попробовать вариант

f1 = Flight.all.first 
f2 = Flight.all.first 

f1.eql? f2 
=> true 

f1 == f2 
=> true 

f1.equal? f2 # Direct Object comparison (skips ActiveRecord::Base) 
=> false 
+0

Благодарим вас за подробное объяснение. Я знаю равных? тесты для «одинаковости» объектов. Я использовал его здесь, чтобы продемонстрировать, что это не тот же объект. Моя проблема не проверяется на равенство. Проблема в том, что мне нужно вернуть тот же объект, а не новый. Меня беспокоит различное поведение активной записи, когда я использую условия. – davidrac

+0

'Проблема в том, что мне нужно вернуть тот же объект, а не только что созданный.' И проблема заключается в том, что вы не можете этого сделать, повторно запросив базу данных. Из-за этого фундаментального факта (два идентичных запроса для одной записи дают два ** разных объекта Ruby), ваш пример ошибочен.Может быть, если вы предоставите более подходящий пример, в котором точно указано, что вы пытаетесь сделать, я могу помочь дальше. – deefour

+0

OK дайте мне объяснение. используя 'inverse_of', я добрался до точки, где я могу получить исходный объект полета из Сидений, которые были получены с помощью' first' и 'last':' s1.flight.equal? s2.flight'. Но когда я получил Сиденье с условием (где), я больше не получаю первоначальный полет. Причина, по которой мне нужен исходный объект, заключается в том, что я использую его для некоторого простого кэширования некоторых результатов вычислений, и я хочу избежать перекомпоновки. – davidrac

0

Inverse_of не работает с условиями, поэтому s1.flight и s3.flight не равны - ActiveRecord просто перезагружает объект из базы данных, когда вы делаете s3.flight. Это, как представляется, документированное поведение, см. https://github.com/rails/rails/issues/23693#issuecomment-184438933

Смежные вопросы