Je soumets un paramètre show_all
avec la valeur true
. Cette valeur n'est pas associée à un modèle.
Mon contrôleur attribue ce paramètre à une variable d'instance:
@show_all = params[:show_all]
Cependant, @show_all.is_a? String
et if @show_all == true
échouent toujours.
Quelles sont les valeurs analysées par Rails en tant que booléens? Comment puis-je spécifier explicitement que mon paramètre est un booléen et non une chaîne?
Je voulais faire un commentaire sur la réponse zététique, mais comme je ne peux pas le faire pour le moment, je le posterai en tant que réponse.
Si tu utilises
@show_all = params[:show_all] == "1"
alors vous pouvez supprimer ? true : false
car l'instruction params[:show_all] == "1"
sera évaluée comme étant vraie ou fausse et qu'un opérateur ternaire n'est donc pas nécessaire.
MISE À JOUR: Rails 5:
ActiveRecord::Type::Boolean.new.deserialize('0')
UPDATE: Rails 4.2 a une API publique pour cela:
ActiveRecord::Type::Boolean.new.type_cast_from_user("0") # false
RÉPONSE PRÉCÉDENTE:
ActiveRecord conserve une liste de représentations pour true/false dans 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")
Cela ne fait pas partie de l'API publique de Rails, je l'ai donc intégrée dans une méthode d'assistance:
class ApplicationController < ActionController::Base
private
def parse_boolean(value)
ActiveRecord::ConnectionAdapters::Column.value_to_boolean(value)
end
end
et ajouté un test de base:
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
Cette question est plutôt ancienne, mais comme je suis tombée sur cette question à quelques reprises et que je n’aimais aucune des solutions proposées, j’ai moi-même piraté quelque chose qui permet d’utiliser plusieurs chaînes pour true, telles que 'oui' , 'on', 't' et le contraire pour false.
Monkey corrige la classe String, et ajoute une méthode pour les convertir en booléen, et place ce fichier dans /config/initializers
comme suggéré ici: Corriger les singes dans 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
Notez que si la valeur n'est aucune des valeurs valides, que ce soit pour true ou false, elle renvoie nil. Ce n'est pas la même chose que de rechercher ?paid=false
(renvoyer tous les enregistrements non payés) à ?paid=
(je ne précise pas si cela doit être payé ou non, alors ignorez ceci).
Ensuite, en suivant cet exemple, la logique de votre contrôleur ressemblerait à ceci:
Something.where(:paid => params[:paid].to_bool) unless params[:paid].try(:to_bool).nil?
C'est très soigné, et aide à garder les contrôleurs/modèles propres.
@show_all = params[:show_all] == "1" ? true : false
Cela devrait fonctionner correctement si vous passez la valeur d'une case à cocher - une clé manquante dans un hachage génère nil, ce qui donne False dans une condition.
MODIFIER
Comme souligné ici , l'opérateur ternaire n'est pas nécessaire, il peut donc s'agir simplement:
@show_all = params[:show_all] == "1"
Vous pouvez modifier votre déclaration d'égalité en:
@show_all == "true"
Si vous voulez que ce soit un booléen, vous pouvez créer une méthode sur la classe string pour convertir une chaîne en boolean.
Je pense que la solution la plus simple est de tester les paramètres "booléens" par rapport à leur représentation String.
@show_all = params[:show_all]
if @show_all.to_s == "true"
# do stuff
end
Indépendamment du fait que Rails fournisse le paramètre sous la forme de chaîne "true" ou "false" ou d'une TrueClass ou FalseClass réelle, ce test fonctionnera toujours.
Vous pouvez convertir tous vos paramètres booléens en vrais booléens comme ceci:
%w(show_all, show_featured).each do |bool_param|
params[bool_param.to_sym] = params[bool_param.to_sym] == "true"
end
Dans cette solution, les paramètres nil deviendraient faux.
Vous pouvez ajouter les éléments suivants à votre modèle:
def show_all= value
@show_all = ActiveRecord::ConnectionAdapters::Column.value_to_boolean(value)
end
Une autre approche consiste à ne transmettre que la clé sans valeur. Bien que l’utilisation de ActiveRecord::Type::Boolean.new.type_cast_from_user(value)
soit assez simple, il peut arriver que l’attribution d’une valeur à la clé param soit redondante.
Prenez en compte les éléments suivants: Par défaut, je souhaite afficher uniquement la collection étendue de produits (par exemple, ceux qui sont en stock). C'est-à-dire que si je veux renvoyer tous les produits, je peux envoyer myapp.com/products?show_all=true
et saisir le paramètre show_all
avec une valeur booléenne.
Cependant, l'option inverse - myapp.com/products?show_all=false
n'a aucun sens, car elle renverra la même collection de produits que celle que myapp.com/products
aurait renvoyée.
Une alternative:
si je veux renvoyer la collection entière non recouverte, j'envoie myapp.com/products?all
et, dans mon contrôleur, je définis
private
def show_all?
params.key?(:all)
end
Si la clé est présente dans les paramètres, quelle que soit sa valeur, je saurai que je dois renvoyer tous les produits, pas besoin de transtyper une valeur.