我正在尝试在SQLite3表中插入一个false布尔值,但它总是插入一个真值。
这是我的迁移:
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
当我尝试使用rails进行插入时,会产生以下SQL:
INSERT INTO "users" ("name", "active") VALUES ('test', 'f')
SQLite将'f'视为true,因此它将true插入到我的数据库中。我希望它生成的查询是:
INSERT INTO "users" ("name", "active") VALUES ('test', false)
我做错了什么?
rails:3.0.7
sqlite3 gem:1.3.3
答案 0 :(得分:21)
SQLite使用1 for true and 0 for false:
SQLite没有单独的布尔存储类。相反,布尔值存储为整数0(假)和1(真)。
但SQLite也有一个松散的类型系统并自动转换东西,因此你的'f'
可能被解释为具有“真实”的真实性,仅仅因为它不是零。
有点挖掘表明您在Rails 3.0.7 SQLiteAdapter中发现了一个错误。在active_record/connection_adapters/abstract/quoting.rb
中,我们找到了这些:
def quoted_true
"'t'"
end
def quoted_false
"'f'"
end
因此,默认情况下,ActiveRecord假定数据库理解布尔列的't'
和'f'
。 MySQL适配器会覆盖它们以使用其布尔列的tinyint
实现:
QUOTED_TRUE, QUOTED_FALSE = '1'.freeze, '0'.freeze
#...
def quoted_true
QUOTED_TRUE
end
def quoted_false
QUOTED_FALSE
end
但SQLite适配器不提供自己的quoted_true
或quoted_false
实现,因此它获得的默认值不适用于SQLite的布尔值。
't'
和'f'
布尔值在PostgreSQL中工作,所以也许每个人都在使用PostgreSQL和Rails 3,或者他们只是没有注意到他们的查询无法正常工作。
我对此感到有些惊讶,希望有人可以指出我出错的地方,你不能成为第一个在SQLite中使用Rails 3的布尔列的人。
尝试将def quoted_true;'1';end
和def quoted_false;'0';end
修补到ActiveRecord::ConnectionAdapters::SQLiteAdapter
(或暂时将其手动编辑为active_record/connection_adapters/sqlite_adapter.rb
)并查看是否获得了合理的SQL。
答案 1 :(得分:4)
我也碰到了这个,这里是如何修补补丁:
require 'active_record/connection_adapters/sqlite_adapter'
module ActiveRecord
module ConnectionAdapters
class SQLite3Adapter < SQLiteAdapter
def quoted_true; '1' end
def quoted_false; '0' end
end
end
end
我不明白我是如何运行这个错误的?
答案 2 :(得分:3)
您可能会发现以下代码片段用于添加与实际使用Rails 4的SQLite布尔列的兼容性(也发布在https://gist.github.com/ajoman/9391708):
# config/initializers/sqlite3_adapter_patch.rb
module ActiveRecord
module ConnectionAdapters
class SQLite3Adapter < AbstractAdapter
QUOTED_TRUE, QUOTED_FALSE = "'t'", "'f'"
def quoted_true
QUOTED_TRUE
end
def quoted_false
QUOTED_FALSE
end
end
end
end
答案 3 :(得分:2)
这是2017年7月12日的主人fixed。但它是not part of the latest stable release (5.1.4)。已修复的最新版本为v5.2.0.rc1。
可以通过Rails.application.config.active_record.sqlite3.represent_boolean_as_integer
(default is true
)设置行为。
答案 4 :(得分:0)
此版本适用于Rails 4.1。
require 'active_record/connection_adapters/sqlite_adapter'
module ActiveRecord::ConnectionAdapters::SQLite3Adapter
QUOTED_TRUE, QUOTED_FALSE = 't'.freeze, 'f'.freeze
def quoted_true; QUOTED_TRUE end
def quoted_false; QUOTED_FALSE end
end
常量和.freeze
用于提高性能,因此ruby不必重新生成这些字符串,并在每次调用时收集垃圾。