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