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 gem: 1.3.3

5 ответов


SQLite использует 1 для true и 0 для false:

SQLite не имеет отдельного логического класса хранения. Вместо этого логические значения хранятся в виде целых чисел 0 (false) и 1 (true).

но 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_true или quoted_false таким образом, он получает значения по умолчанию, которые не работают с SQLite логические значения.

на 't' и 'f' booleans работают в PostgreSQL, поэтому, возможно, все используют PostgreSQL с Rails 3 или они просто не замечают, что их запросы работают неправильно.

я немного удивлен этим и, надеюсь, кто-то может указать, где я ошибся, вы не можете быть первым человеком, который использует логический столбец в SQLite с Rails 3.

попробуйте обезьяна ямочный ремонт def quoted_true;'1';end и def quoted_false;'0';end на ActiveRecord::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

Я не понимаю, как я все еще сталкиваюсь с этой ошибкой??


вы можете найти полезным следующий фрагмент кода для добавления совместимости с логическими столбцами SQLite, фактически работающими на Rails 4 (также опубликовано в 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

Это основные на master на 12 июля 2017 года. Однако это не входит в последнюю стабильную версию (5.1.4). Последний выпуск, где это зафиксировано У5.2.0.ник1.

поведение можно установить через 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 не нужно регенерировать эти строки и собирать мусор при каждом вызове.