Rails 3 SQLite3 Boolean false

我试图在SQLite3表中插入一个错误的布尔值,但它总是插入一个真值。

这是我的迁移:

class CreateUsers  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

SQLite使用1表示true,0表示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列的tinyint实现:

 QUOTED_TRUE, QUOTED_FALSE = '1'.freeze, '0'.freeze #... def quoted_true QUOTED_TRUE end def quoted_false QUOTED_FALSE end 

但SQLite适配器不提供自己的quoted_truequoted_false实现,因此它获得了不适用于SQLite的布尔值的默认值。

't''f'布尔值在PostgreSQL中工作,所以也许每个人都使用PostgreSQL和Rails 3,或者他们只是没有注意到他们的查询不能正常工作。

我对此感到有些惊讶,希望有人可以指出我出错的地方,你不能成为第一个在SQLite中使用Rails 3的布尔列的人。

尝试猴子修补def quoted_true;'1';enddef quoted_false;'0';endActiveRecord::ConnectionAdapters::SQLiteAdapter (或暂时手动编辑它们到active_record/connection_adapters/sqlite_adapter.rb ),看看你是否明智SQL。

我也碰到了这个,这里是如何修补补丁:

 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 

我不知道我是如何运行这个错误的?

您可能会发现以下代码片段用于添加与实际使用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 

这是在2017年7月12日在master上修复的 。但它不是最新稳定版本(5.1.4)的一部分 。 它修复的最新版本是v5.2.0.rc1 。

可以通过Rails.application.config.active_record.sqlite3.represent_boolean_as_integer设置行为( 默认为true )。

此版本适用于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不必重新生成这些字符串,垃圾会在每次调用时收集它们。