Just a random discovery that may or may not be a bug - depending on how you look at it.
I recently came across an issue in an application where I was expecting my code to act a certain way and no, so I thought I would share.
I have an ActiveRecord model with a boolean attribute named 'failed'.
I created a class method named 'self.failed' that uses the 'where' clause to check for the 'failed' attribute being true:
And then made an inverse class method named 'self.successful' that uses the 'where.not' clause to check for the failed attribute being not true:
I expected the self.successful class method to return any record where failed != true. After all, it reads 'where failed is not equal to true'. I found that this is slightly misleading when I had 3 total records: the 1st record failed == true, the 2nd failed == false, the 3rd failed == nil.
However, the following is a thing:
Obviously, 1 + 1 does != 3. So the Message where failed == nil was being ignored by the class methods shown above.
The self.successful class method only returns records where failed == false, despite my thinking that it would return anything that was != true.
This makes sense if you rewrite the self.successful method as:
This makes sense that if failed == nil, it would not == false. So.... you have been warned.
If you want to remedy this the proper way, you should set the default to false on the migration of the table (or add a migration to set the default to false).
class CreateSomeModel < ActiveRecord::Migration
def change
create_table :some_model do |t|
t.boolean :failed, default: false
# other stuff here...
end
end
end
Once you establish that the boolean field will either be true or false, and nil is not an option - you can begin to rely on the where.not clause returning the results you expect.
Alternatively, you could write the self.successful class method to include any records that are either failed=false or failed=nil, like so:
Hopefully, this helps someone.