2010-09-09 31 views
55

Estoy enviando un parámetro show_all con el valor true. Este valor no está asociado con un modelo.¿Cómo presento un parámetro booleano en Rails?

Mi controlador es la asignación de este parámetro a una variable de instancia:

@show_all = params[:show_all] 

Sin embargo, @show_all.is_a? String y if @show_all == true siempre falla.

¿Qué valores analiza Rails como booleanos? ¿Cómo puedo especificar explícitamente que mi parámetro sea booleano y no una cadena?

+0

No hay tal cosa como booleanos en rubí, solamente '' TrueClass' y FalseClass' – NullUserException

+1

rieles todavía se lo imagina automágicamente cuando el parámetro está asociado un modelo: si el tipo de columna en la base de datos es booleano, trata el parámetro como 'TrueClass' o' FalseClass'.¿Alguna idea de cómo puedo hacer esto bien? – nfm

+0

posible duplicado de [¿Cómo comprobar si un parámetro es verdadero o falso?] (Http://stackoverflow.com/questions/1711547/how-to-check-if-a-param-is-true-or-false) debido a "¿Hay una forma mejor de hacer esa declaración if/else basada en un param que sea verdadera o falsa?" –

Respuesta

61

quería comentar sobre la respuesta Zetetic pero como pueda' Hago eso, pero lo publicaré como respuesta.

Si utiliza

@show_all = params[:show_all] == "1"

entonces se puede caer debido ? true : falseparams[:show_all] == "1" declaración misma será evaluada como verdadera o falsa y por lo tanto no es necesario operador ternario.

+0

¡Buen punto! Actualicé mi respuesta para reflejar eso. – zetetic

+0

para futuras referencias, esta es la respuesta más limpia. Técnicamente, el booleano se puede pasar como "verdadero" o "falso", pero pasar un número es mejor simplemente porque evita que errores simples como "verdadero" == "Verdadero" devuelvan falso. Ya sea 1, o 0. – sybohy

4

podría cambiar su estado de igualdad a:

@show_all == "true" 

Si usted quiere que sea un valor lógico se podría crear un método en la clase String para convertir una cadena a un valor lógico.

16
@show_all = params[:show_all] == "1" ? true : false 

Esto debería funcionar bien si estás pasando el valor de una casilla de verificación - una clave que falta en un hash genera nula, lo que da como resultado false en una condicional.

EDITAR

Como se ha señalado here, el operador ternario no es necesario, por lo que este solo puede ser:

@show_all = params[:show_all] == "1"

0

Usted puede convertir todos sus parametros buleanos booleanos verdaderos de esta manera:

%w(show_all, show_featured).each do |bool_param| 
    params[bool_param.to_sym] = params[bool_param.to_sym] == "true" 
end 

En esta solución, los parámetros nil se convertirían en falso.

20

Esta pregunta es bastante antigua, pero dado que me encontré con este problema un par de veces, y no me gustó ninguna de las soluciones propuestas, pirateé algo que permite usar varias cadenas para verdadero como ' yes ',' on ',' t 'y lo opuesto a falso.

mono parche de la clase String, y añadir un método para convertirlos a boolean, y poner este archivo en /config/initializers como se sugiere aquí: Monkey Patching in Rails 3

class String 
    def to_bool 
    return true if ['true', '1', 'yes', 'on', 't'].include? self 
    return false if ['false', '0', 'no', 'off', 'f'].include? self 
    return nil 
    end 
end 

Tenga en cuenta que si el valor es ninguno de los válidos, ya sea para verdadero o falso, entonces devuelve nil. No es lo mismo buscar ?paid=false (devolver todos los registros no pagados) que ?paid= (no especifico si debe pagarse o no, así que descarte esto).

Entonces, siguiendo este ejemplo, la lógica en el controlador se vería así:

Something.where(:paid => params[:paid].to_bool) unless params[:paid].try(:to_bool).nil? 

es bastante ordenado, y ayuda a mantener controladores/modelos limpio.

+2

Una excelente solución, limpia, ordenada y agrega una funcionalidad verdaderamente útil a la clase String. Muy agradable. –

+15

Enhorabuena, ahora tiene un 'String # to_bool' que puede devolver' nil'. Por favor, medite en eso por un tiempo, y luego cambie el nombre del método a algo como 'String # maybe_bool?' O recurra a 'ArgumentError'. – Nicos

+2

Esto podría simplificarse aún más como 'def to_bool; ['verdadero', '1', 'sí', 'encendido', 't']. ¿Incluir? yo; end' – lobati

71

ACTUALIZACIÓN: Carriles 5:

ActiveRecord::Type::Boolean.new.deserialize('0') 

ACTUALIZACIÓN: Carriles 4.2 tiene API pública para esto:

ActiveRecord::Type::Boolean.new.type_cast_from_user("0") # false 

respuesta anterior:

ActiveRecord mantiene una lista de las representaciones de verdadero/falso en https://github.com/rails/rails/blob/master/activerecord/lib/active_record/connection_adapters/column.rb

2.0.0-p247 :005 > ActiveRecord::ConnectionAdapters::Column.value_to_boolean("ON") 
2.0.0-p247 :006 > ActiveRecord::ConnectionAdapters::Column.value_to_boolean("F") 

Esto no es parte de la API pública de Rails, así que lo envolvió en un método de ayuda:

class ApplicationController < ActionController::Base 
    private 

    def parse_boolean(value) 
    ActiveRecord::ConnectionAdapters::Column.value_to_boolean(value) 
    end 
end 

y ha añadido una prueba básica:

class ApplicationControllerTest < ActionController::TestCase 
    test "parses boolean params" do 
    refute ApplicationController.new.send(:parse_boolean, "OFF") 
    assert ApplicationController.new.send(:parse_boolean, "T") 
    end 
end 
+3

deberíamos observar sin embargo que 'ActiveRecord :: Type :: Boolean.new.type_cast_from_user (" 0 ")' devolverá 'false' como usted mencionó, pero en Rails 5 comenzará a devolver true: DEPRECATION WARNING: Intentó asignar un valor que no es explícitamente 'verdadero' o 'falso' a una columna booleana. Actualmente este valor arroja a 'falso'. Esto cambiará para coincidir con la semántica de Ruby, y se convertirá en 'verdadero' en Rails 5. Si desea mantener el comportamiento actual, debe manejar explícitamente los valores que le gustaría convertir a 'false'. –

+1

'ActiveRecord :: Type :: Boolean' es solo un alias de' ActiveModel :: Type :: Boolean'. Probablemente sea un poco mejor usar la clase original. –

1

creo que la solución más simple es poner a prueba parámetros "booleanos" contra su representación de cadena.

@show_all = params[:show_all] 
if @show_all.to_s == "true" 
    # do stuff 
end 

Independientemente de si Rails saca el parámetro como la cadena "verdadero" o "falso" o un TrueClass real o FalseClass, esta prueba siempre funcionará.

0

Otro enfoque es pasar solo la llave sin un valor. Aunque el uso de ActiveRecord::Type::Boolean.new.type_cast_from_user(value) es bastante limpio, puede haber una situación en la que la asignación de un valor a la clave param sea redundante.

Considere lo siguiente: En la vista de índice de mis productos, de forma predeterminada, deseo mostrar solo la colección con ámbito de productos (por ejemplo, los que están en stock). Es decir, si deseo devolver todos los productos, puedo enviar myapp.com/products?show_all=true y encasillar el parámetro show_all para un valor booleano.

Sin embargo, la opción opuesta - myapp.com/products?show_all=false simplemente no tiene sentido ya que devolverá la misma colección de productos que myapp.com/products habría devuelto.

Una alternativa:

si quiero devolver toda la colección sin ámbito, después envío myapp.com/products?all y en mi controlador de definir

private 

def show_all? 
    params.key?(:all) 
end 

Si la clave está presente en params, a continuación, independientemente de su valor , Sabré que necesito devolver todos los productos, sin necesidad de valor de conversión.

0

Puede añadir lo siguiente a su modelo:

def show_all= value 
    @show_all = ActiveRecord::ConnectionAdapters::Column.value_to_boolean(value) 
end 
Cuestiones relacionadas