Rails: Почему вы не можете установить ассоциацию на ноль в предложении where? - PullRequest
9 голосов
/ 06 марта 2011

У меня есть фотографии, которые принадлежат коллекциям и пользователям.Фотографии всегда принадлежат пользователю, но не могут быть назначены коллекции.

В моем контроллере это работает отлично:

@collection_photos = Photo.where( :collection => @collection, :user => current_user )

Однако это не удается ...

@other_photos = Photo.where( :collection => nil, :user => current_user )

... но это работает:

@other_photos = Photo.where( :collection_id => nil, :user => current_user )

Когда для коллекции установлено значение nil, я получаю это сообщение об ошибке: No attribute named 'collection' exists for table photos.

Если я передаю объект, онумеет искать collection_id по символу :collection, но если я не пропущу объект, он, похоже, не осознает ассоциации.

Правильно ли я понимаю?Кто-нибудь может объяснить немного лучше, почему :collection=>nil не работает?

Ответы [ 4 ]

3 голосов
/ 09 марта 2011

Я думаю, что ваш ответ в ActiveRecord::PredicateBuilder.build_from_hash. Там есть оператор case, который проверяет класс каждого значения в хэше, и он специально ищет ActiveRecord::Relation

3 голосов
/ 09 марта 2011

когда вы используете pass в условиях в ActiveRecord, он на самом деле пытается проанализировать объекты, которые вы передали, это строка?массив?хэш?и что находится в строке, массиве или хэше?

и в вашем случае хеш, поэтому он пытается проанализировать, что находится в хэше, в первом операторе (который работает), который вы передали в экземпляре модели какзначение, поэтому он пытается найти, есть ли ассоциации, которые сопоставлены с указанным вами ключом и вуаля, он нашел его, и все работает как запланировано

во втором случае, вы передали в качестве значения значение nil,теперь ActiveRecord видит, что это нулевой объект, поэтому он решил, что это не ассоциация.обратите внимание, что он не смотрит на ключ, а только смотрит на значение, поэтому он пытается найти какой-либо столбец, который сопоставлен с ключом, но не может найти, возвращая ошибку

в последнем случае вы передали nil в качестве значения, то же самое, он попытался найти столбец, сопоставленный с: collection_id, таким образом, он передал nil в качестве значения в операторе SQL и успешно возвратил

так что ActiveRecord просто прискорбно принимает во внимание второй случай, когда второй случай не работает =)

надеюсь, это прояснится!= D

3 голосов
/ 06 марта 2011

Полагаю, это как знаменитые рельсы .find vs .find_by_id .

.find предназначен для исключения, если не может найти никакой связи.

где as .find_by_id просто вернет ноль, если не найдет никакой связи.

так в вашем выражении .where , когда вы ищете коллекцию, это, вероятно, трактует это как .find , и когда вы ищете по collection_id, она вернет nil точно так же, как .find_by_id делает, если не может найти связанную коллекцию.

Я не уверен, насколько эти два метода отличаются во внутренней работе Activerecord, но они предназначены для того, чтобы по-разному реагировать на нулевые результаты.

0 голосов
/ 23 марта 2015

Это, похоже, больше не проблема в Rails 4. Например, следующий код

@other_photos = Photo.where( :collection => nil, :user => User.first )

будет работать

User Load (Xms)  SELECT  "users".* FROM "users"   ORDER BY "users"."id" ASC LIMIT 1
Photo Load (Xms)  SELECT "photos".* FROM "photos"  WHERE "photos"."collection_id" IS NULL AND "photos"."user_id" = 1

* Протестировано в Rails 4.1.1

...