Rails 3 SQLite3 布尔值 false
我试图在 SQLite3 表中插入一个假布尔值,但它总是插入一个真值。
这是我的迁移:
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)
我做错了什么?
导轨:3.0.7
sqlite3 宝石:1.3.3
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
SQLite 使用 1 表示 true,0 表示 false:
但是 SQLite 也有一个松散的类型系统,并且会自动进行转换,因此您的
'f'
可能会被解释为具有“true”的真实性,仅仅是因为它不为零。经过一番挖掘,您发现了 Rails 3.0.7 SQLiteAdapter 中的一个错误。在
active_record/connection_adapters/abstract/quoting.rb
中,我们找到以下内容:因此,默认情况下,ActiveRecord 假定数据库理解
't'
和'f'
用于布尔列。 MySQL 适配器会覆盖这些以与其布尔列的tinyint
实现一起使用:但 SQLite 适配器不提供自己的
quoted_true
或quoted_false
实现所以它得到的默认值不适用于 SQLite 的布尔值。't'
和'f'
布尔值在 PostgreSQL 中工作,所以也许每个人都在 Rails 3 中使用 PostgreSQL,或者他们只是没有注意到他们的查询无法正常工作。我对此感到有点惊讶,希望有人能指出我哪里出错了,你不可能是第一个在 SQLite 和 Rails 3 中使用布尔列的人。
尝试猴子修补
defquoted_true;' 1';end
和defquoted_false;'0';end
到ActiveRecord::ConnectionAdapters::SQLiteAdapter
中(或临时手动将它们编辑到active_record/connection_adapters/sqlite_adapter.rb
) 并查看是否获得合理的 SQL。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 itstinyint
implementation of boolean columns:But the SQLite adapter does not provide its own implementations of
quoted_true
orquoted_false
so 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';end
anddef quoted_false;'0';end
intoActiveRecord::ConnectionAdapters::SQLiteAdapter
(or temporarily hand-edit them intoactive_record/connection_adapters/sqlite_adapter.rb
) and see if you get sensible SQL.我也遇到了这个问题,以下是如何进行猴子补丁:
我不明白我是如何仍然遇到这个错误的?
I ran across this as well, here's how to monkey patch:
I don't get how I'm still running across this bug??
您可能会发现以下代码片段非常有用,可用于添加与实际在 Rails 4 上运行的 SQLite 布尔列的兼容性(也发布于 https ://gist.github.com/ajoman/9391708):
You may find useful the following code snippet for adding compatibility with SQLite boolean columns actually working on Rails 4 (also posted at https://gist.github.com/ajoman/9391708):
此问题已于 2017 年 7 月 12 日在 master 上修复。但是不属于最新稳定版本 (5.1.4)。修复该问题的最新版本是 v5.2.0.rc1。
可以通过 Rails.application.config.active_record.sqlite3.represent_boolean_as_integer 设置行为(默认值为
true
)。This was fixed on master on 12 Jul 2017. However it is not part of the latest stable release (5.1.4). The most recent release where it's fixed is v5.2.0.rc1.
The behaviour can be set via
Rails.application.config.active_record.sqlite3.represent_boolean_as_integer
(default istrue
).该版本适用于 Rails 4.1。
常量和 .freeze 是为了提高性能,因此 ruby 不必在每次调用时重新生成这些字符串并进行垃圾收集。
This version works in Rails 4.1.
The constants and
.freeze
are for performance, so ruby doesn't have to regenerate those strings and garbage collect them on every call.