I’m trying to insert a false boolean value in a SQLite3 table but it always inserts a true value.
Here’s my migration:
class CreateUsers < ActiveRecord::Migration
def self.up
create_table :users do |t|
t.column :name, :string
t.column :active, :boolean, :default => false, :null => false
end
end
def self.down
drop_table :resources
end
end
When I try to insert using rails it produces the following SQL:
INSERT INTO "users" ("name", "active") VALUES ('test', 'f')
SQLite treats ‘f’ as true so it inserts true into my database. The query I want it to generate is:
INSERT INTO "users" ("name", "active") VALUES ('test', false)
What am I doing wrong?
rails: 3.0.7
sqlite3 gem: 1.3.3
SQLite uses 1 for true and 0 for false:
But SQLite also has a loose type system and automatically casts things so your
'f'is probably being interpreted as having a truthiness of “true” simply because it isn’t zero.A bit of digging indicates that you have found a bug in the Rails 3.0.7 SQLiteAdapter. In
active_record/connection_adapters/abstract/quoting.rb, we find these:So, by default, ActiveRecord assumes that the database understands
't'and'f'for boolean columns. The MySQL adaptor overrides these to work with itstinyintimplementation of boolean columns:But the SQLite adapter does not provide its own implementations of
quoted_trueorquoted_falseso it gets the defaults which don’t work with SQLite’s booleans.The
't'and'f'booleans work in PostgreSQL so maybe everyone is using PostgreSQL with Rails 3 or they’re just not noticing that their queries aren’t working properly.I’m a little surprised by this and hopefully someone can point out where I’ve gone wrong, you can’t be the first person to use a boolean column in SQLite with Rails 3.
Try monkey patching
def quoted_true;'1';endanddef quoted_false;'0';endintoActiveRecord::ConnectionAdapters::SQLiteAdapter(or temporarily hand-edit them intoactive_record/connection_adapters/sqlite_adapter.rb) and see if you get sensible SQL.