I have photos that belong to collections and users. Photos always belong to a user, but may not be assigned to a collection.
In my controller, this works perfectly:
@collection_photos = Photo.where( :collection => @collection, :user => current_user )
However, this fails...
@other_photos = Photo.where( :collection => nil, :user => current_user )
...but this works:
@other_photos = Photo.where( :collection_id => nil, :user => current_user )
When collection is set to nil I get this error message: No attribute named 'collection' exists for table photos
.
If I pass an object, it knows to search for collection_id
from the symbol :collection
, but if I don't pass an object it doesn't seem to be aware of the association.
Am I understanding this correctly? Could anyone explain a little better why :collection=>nil
doesn't work?
when you use pass in the conditions into ActiveRecord, it actually tries to analyze the objects that you passed in, is it a string? an array? a hash? and what's in the string, array or hash?
and in your case, a hash, so it's trying to analyze what's in the hash, in the first statement (which works), you passed in a model instance as the value, so it tries to find if there are any associations that mapped to the key your specified and voila, it found it and everything works as planned
in the second case, you passed in nil as the value, now, ActiveRecord sees that it's a nil object, so it decided that it's not an association. note that it doesn't look at the key, but it only looked at the value, thus it tries to find if there's any column that mapped to the key, but it couldn't find, returning an error
in the last case, you passed in nil as the value, same thing, it tried to find a column which mapped to :collection_id, thus it passed in nil as the value in the SQL statement, and it returned successfully
so it's just an unfortunate considerations taken by ActiveRecord that makes the second case not working =)
hope this clarifies! =D
My guess is that it's like the famous rails .find vs .find_by_id.
.find is designed to throw an exception if it cannot find any association.
where as .find_by_id will just return nil if doesn't find any association.
so in your .where statement, when you search for the collection it's probably treating that like a .find and when you search by collection_id it will return nil just like .find_by_id does if it can't find any associated collection.
I'm not sure how these two methods differ in Activerecord's inner workings, but they are designed to react differently to nil results.
I think your answer is in ActiveRecord::PredicateBuilder.build_from_hash
. There is a case statement in there that checks the class of each value in the hash, and it specifically looks for ActiveRecord::Relation
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With