This may seem a minor issue, but I think it's worth a bit of discussion to get it right. Let me start with the use case that led me smack into the issue.
Start with some model that has a boolean field that can be nil/null. Create a view with a form that uses a select box to set the field's value, and set :include_blank => true. The obvious assumption is that if you select blank (as opposed to Yes/1/true or No/0/false), the field value will be saved as nil/null. Not so - it is saved as 0/false. This has the weird behavior of the select box showing the false choice when you select blank and get bounced back for a second try at the form.
create_table :widgets do |t| t.string :name t.boolean :fancy end
w = Widget.create(:name => "weather", :fancy => true) w.fancy # => true w.update_attributes(:fancy => nil) w.fancy # => nil w.update_attributes(:fancy => "") w.fancy # => false
It's not too much trouble to patch ActiveRecord to change it so that setting a boolean field to a blank string gets saved as NULL in the database instead of 0. The question is: what is the desired behavior? More specifically, when should the value be coerced, with special consideration to the case when the field doesn't allow a nil/NULL value?
I think the answer is that blank values should always be coerced to nil in memory, even when the field is created with :null => false. This is consistent with how integer fields are handled. You can have a nil value in memory, and the db will barf when you try and save it as NULL. AR expects you to use a validation to catch that and give the user another shot at the form. However... there is what looks to me like a bug in AR where assigning a blank-but-not-empty string to an integer field has a different result from assigning an empty string or nil. An empty string is coerced to nil, but a string of one or more whitespace characters is coerced to 0. It's also easy to fix it so that all blank strings are coerced to 0, and I think that would be the best thing to do. But I wonder if anyone out there might be relying on this behavior. There are only 2 tests that break when this change is made (in validations_test.rb).
By the way, strings representing integers are coerced to their correct values, but non-numeric objects like arrays and hashes are coerced to 1. WTF? Why is that useful?
I was going to create a ticket with a patch for this stuff to refer to, but the code is sitting on a computer at work so that won't happen until the morning (sorry, Pratik).
To summarize:
I propose that all blank strings should be coerced to nil, for both boolean and integer fields. Any issues with that? Anyone know if they are relying on that behavior?