Rails 3 SQLite3 布尔值 false

发布于 2024-11-07 18:12:48 字数 679 浏览 10 评论 0 原文

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

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

我纯我任性 2024-11-14 18:12:48

SQLite 使用 1 表示 true,0 表示 false

SQLite 没有单独的布尔存储类。相反,布尔值存储为整数 0(假)和 1(真)。

但是 SQLite 也有一个松散的类型系统,并且会自动进行转换,因此您的 'f' 可能会被解释为具有“true”的真实性,仅仅是因为它不为零。

经过一番挖掘,您发现了 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,或者他们只是没有注意到他们的查询无法正常工作。

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

尝试猴子修补 defquoted_true;' 1';enddefquoted_false;'0';endActiveRecord::ConnectionAdapters::SQLiteAdapter 中(或临时手动将它们编辑到 active_record/connection_adapters/sqlite_adapter.rb) 并查看是否获得合理的 SQL。

SQLite uses 1 for true and 0 for false:

SQLite does not have a separate Boolean storage class. Instead, Boolean values are stored as integers 0 (false) and 1 (true).

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:

def quoted_true
  "'t'"
end

def quoted_false
  "'f'"
end

So, by default, ActiveRecord assumes that the database understands 't' and 'f' for boolean columns. The MySQL adaptor overrides these to work with its tinyint implementation of boolean columns:

QUOTED_TRUE, QUOTED_FALSE = '1'.freeze, '0'.freeze

#...

def quoted_true
  QUOTED_TRUE
end

def quoted_false
  QUOTED_FALSE
end

But the SQLite adapter does not provide its own implementations of quoted_true or quoted_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 and def quoted_false;'0';end into ActiveRecord::ConnectionAdapters::SQLiteAdapter (or temporarily hand-edit them into active_record/connection_adapters/sqlite_adapter.rb) and see if you get sensible SQL.

秋日私语 2024-11-14 18:12:48

我也遇到了这个问题,以下是如何进行猴子补丁:

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

我不明白我是如何仍然遇到这个错误的?

I ran across this as well, here's how to monkey patch:

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

I don't get how I'm still running across this bug??

风吹雨成花 2024-11-14 18:12:48

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

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):

# 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
单身狗的梦 2024-11-14 18:12:48

此问题已于 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 is true).

梦中的蝴蝶 2024-11-14 18:12:48

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

This version works in 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

The constants and .freeze are for performance, so ruby doesn't have to regenerate those strings and garbage collect them on every call.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文