Rails 3 SQLite3 Boolean false

时间:2011-05-16 04:16:50

标签: ruby-on-rails ruby-on-rails-3 sqlite rails-activerecord

我正在尝试在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

5 个答案:

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

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

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

尝试将def quoted_true;'1';enddef 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_integerdefault 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不必重新生成这些字符串,并在每次调用时收集垃圾。