Rails 3 SQLite3 布尔值 false

Posted

技术标签:

【中文标题】Rails 3 SQLite3 布尔值 false【英文标题】:Rails 3 SQLite3 Boolean false 【发布时间】:2011-08-26 04:02:05 【问题描述】:

我试图在 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

【问题讨论】:

你的 Rails 代码用 'f' 生成 SQL 是什么? 生成的 html 如下所示: 控制器是一个简单的 REST 创建。 即使我执行如下查询:User.find(:all, :conditions => :active => false) sql 看起来像这样:SELECT "users".* FROM "users " WHERE "用户"."active" = 'f' 【参考方案1】:

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_truequoted_false 实现,因此它获得了不适用于 SQLite 布尔值的默认值。

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

对此我有点惊讶,希望有人能指出我哪里出错了,你不可能是第一个在 Rails 3 中使用 SQLite 布尔列的人。

尝试将 def quoted_true;'1';enddef quoted_false;'0';end 修改为 ActiveRecord::ConnectionAdapters::SQLiteAdapter(或暂时将它们手动编辑为 active_record/connection_adapters/sqlite_adapter.rb),看看您是否获得了合理的 SQL。

【讨论】:

是的,我知道这一点。我只是不知道为什么它使用 'f' 而不是 false 或 0,因为 0 在 POST 中传递。 @Mike:请看一下我的更新。我删除了我原来的答案,然后将其复活,并根据对 ActiveRecord 数据库适配器源代码的快速回顾进行了更新。 这就是我的想法...我不能成为第一个遇到这个错误的人,这让我认为这与我的环境有关。我会稍等一下,看看其他人是否有其他解释,否则我会给你功劳。 原来 sqlite 适配器没有问题。这是我的数据库查看软件,其中有错误。非常感谢您的深入回答,我希望我能给您功劳。 @Mike:Rails 在 SQLite 数据库中使用 't''f' 作为布尔值,对吧?只要只有 Rails 使用数据库就可以正常工作,SQLite 在内部将所有内容都视为字符串,因此 DDL 中的列类型主要是建议性的。我只是好奇我是否正确阅读了源代码,也许我会设置自己的 Rails/SQLite 测试应用程序看看。【参考方案2】:

我也遇到过,这里是猴子补丁的方法:

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

我不明白我是怎么遇到这个错误的??

【讨论】:

使用 't' 和 'f' 而不是 '1' 和 '0'。这应该是评论,而不是答案。 这不适用于 Rails 5。你有更新版本吗?【参考方案3】:

您可能会发现以下代码 sn-p 对于添加与实际在 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

【讨论】:

这不适用于 Rails 5。你有更新版本吗? @thisismydesign 抱歉,我没有更新版本,因为我不再使用 SQLite 在 Rails 上进行开发。【参考方案4】:

这是 2017 年 7 月 12 日在 master 上的 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) 设置行为。

【讨论】:

【参考方案5】:

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

【讨论】:

以上是关于Rails 3 SQLite3 布尔值 false的主要内容,如果未能解决你的问题,请参考以下文章

将字符串“true”和“false”转为布尔值

Rails4迁移 - 向add_reference方法添加null:false?

在Flask-SQLAlchemy中使用SQLite3时模拟布尔值的ARRAY

布尔值数据类型

如何在 SQLite3 和 Rails 3.1 中打开 REGEXP?

Day3:数据类型(布尔值集合)