Rails 3 SQLite3 Booleano falso

Estoy tratando de insertar un valor booleano falso en una tabla SQLite3 pero siempre inserta un valor verdadero.

Aquí está mi migración:

class CreateUsers  false, :null => false end end def self.down drop_table :resources end end 

Cuando bash insertar usando raíles produce el siguiente SQL:

 INSERT INTO "users" ("name", "active") VALUES ('test', 'f') 

SQLite considera que ‘f’ es verdadero, por lo que se inserta verdadero en mi base de datos. La consulta que quiero que genere es:

 INSERT INTO "users" ("name", "active") VALUES ('test', false) 

¿Qué estoy haciendo mal?

Rails: 3.0.7

gem sqlite3: 1.3.3

SQLite usa 1 para verdadero y 0 para falso

SQLite no tiene una clase de almacenamiento booleana separada. En cambio, los valores booleanos se almacenan como enteros 0 (falso) y 1 (verdadero).

Pero SQLite también tiene un sistema de tipo suelto y automáticamente arroja las cosas para que tu 'f' probablemente se interprete como que tiene una verdad de “verdad” simplemente porque no es cero.

Un poco de excavación indica que ha encontrado un error en Rails 3.0.7 SQLiteAdapter. En active_record/connection_adapters/abstract/quoting.rb , encontramos esto:

 def quoted_true "'t'" end def quoted_false "'f'" end 

Por lo tanto, de forma predeterminada, ActiveRecord supone que la base de datos comprende 't' y 'f' para las columnas booleanas. El adaptador MySQL anula estos para trabajar con su implementación tinyint de columnas booleanas:

 QUOTED_TRUE, QUOTED_FALSE = '1'.freeze, '0'.freeze #... def quoted_true QUOTED_TRUE end def quoted_false QUOTED_FALSE end 

Pero el adaptador SQLite no proporciona sus propias implementaciones de quoted_true o quoted_false por lo que obtiene los valores predeterminados que no funcionan con los booleanos de SQLite.

Los booleanos 't' y 'f' funcionan en PostgreSQL así que quizás todo el mundo esté usando PostgreSQL con Rails 3 o simplemente no se dan cuenta de que sus consultas no funcionan correctamente.

Estoy un poco sorprendido por esto y espero que alguien pueda señalar dónde me he equivocado, no puede ser la primera persona en usar una columna booleana en SQLite con Rails 3.

Pruebe el parche de mono def quoted_true;'1';end y def quoted_false;'0';end en ActiveRecord::ConnectionAdapters::SQLiteAdapter (o ActiveRecord::ConnectionAdapters::SQLiteAdapter manualmente a mano en active_record/connection_adapters/sqlite_adapter.rb ) y vea si tiene sentido SQL.

Me encontré con esto también, así es como parche de mono:

 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 

No entiendo cómo sigo corriendo por este error?

Puede encontrar útil el siguiente fragmento de código para agregar compatibilidad con las columnas booleanas SQLite que realmente funcionan en Rails 4 (también publicado en 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 

Esto se arregló en el maestro el 12 de julio de 2017. Sin embargo, no forma parte de la última versión estable (5.1.4) . La versión más reciente donde se solucionó es v5.2.0.rc1 .

El comportamiento se puede establecer a través de Rails.application.config.active_record.sqlite3.represent_boolean_as_integer (el valor predeterminado es true ).

Esta versión funciona en 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 

Las constantes y .freeze son para el rendimiento, por lo que ruby ​​no tiene que .freeze a generar esas cadenas y recogerlas en cada llamada.