2011-05-16 20 views
9

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

Aquí es mi migración:

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 

Cuando intento para insertar el uso de rieles que produce el siguiente SQL:

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

SQLite golosinas 'f' como verdadero lo que introduce cierto en mi base de datos. La consulta que quiero que genere es:

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

¿Qué estoy haciendo mal?

rieles: 3.0.7

sqlite3 joya: 1.3.3

+0

¿Cuál es el código de sus raíles que produce el SQL con 'f'? –

+0

El HTML generado se ve así:


Mike

+0

El controlador es un simple REST crear. – Mike

Respuesta

21

SQLite utiliza 1 for true and 0 for false:

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

Pero SQLite también tiene un sistema de tipos sueltos y automáticamente pone las cosas para que su 'f' probablemente se interpreta como tener un truthiness de la "verdadera", 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 los siguientes:

def quoted_true 
    "'t'" 
end 

def quoted_false 
    "'f'" 
end 

Así que, por defecto, ActiveRecord asume que la base de datos entiende 't' y 'f' para las columnas booleanas. El adaptador de MySQL anula estos para trabajar con su tinyint implementación 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 de SQLite no proporciona sus propias implementaciones de quoted_true o quoted_false por lo que obtiene los valores por defecto que no funcionan con los booleanos de SQLite.

Los booleanos 't' y 'f' funcionan en PostgreSQL así que quizás todos estén 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 puede señalar dónde he ido mal, no puede ser la primera persona en utilizar una columna booleana en SQLite con rieles mono 3.

Try parcheando def quoted_true;'1';end y def quoted_false;'0';end en ActiveRecord::ConnectionAdapters::SQLiteAdapter (o edítelos manualmente a mano en active_record/connection_adapters/sqlite_adapter.rb) y vea si obtiene SQL razonable.

+0

Sí, soy consciente de eso. Simplemente no puedo entender por qué está usando 'f' en lugar de falso o 0 porque se pasa un 0 en el POST. – Mike

+0

@Mike: echa un vistazo a mi actualización, por favor. Eliminé mi respuesta original, luego la resucité y la actualicé en base a una revisión rápida del código fuente del adaptador de la base de datos ActiveRecord. –

+0

Eso es lo que estaba pensando ... No puedo ser la primera persona en encontrar este error que me hizo pensar que era algo relacionado con mi entorno. Esperaré un poco para ver si alguien más tiene otra explicación, de lo contrario le daré el crédito. – Mike

4

me encontré con esto también, así es como parche 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 todavía estoy corriendo a través de este error ??

+0

Use 't' y 'f' en lugar de '1' y '0'. Esto debería haber sido un comentario, no una respuesta. –

+0

Esto no funciona para mí con Rails 5. ¿Tiene una versión actualizada? – thisismydesign

3

Usted puede encontrar útil el siguiente fragmento de código para añadir compatibilidad con columnas booleanas SQLite en realidad trabajan en los carriles 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 
+0

Esto no funciona para mí con Rails 5. ¿Tiene una versión actualizada? – thisismydesign

+0

@thisismydesign lo siento, no tengo una versión actualizada ya que no estoy usando más SQLite para el desarrollo en Rails. –

0

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 no tiene rubí para regenerar esas cadenas y la basura que recoger en cada llamada.