web-dev-qa-db-fra.com

Comment envoyer un paramètre booléen dans Rails?

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?

63
nfm

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.

66
Uģis Ozols

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
85
Wojtek Kruszewski

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.

21
ismriv
@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"

17
zetetic

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.

4
benr75

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.

2
Jeremy Burton

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.

0
fisherwebdev

Vous pouvez ajouter les éléments suivants à votre modèle:

def show_all= value
  @show_all = ActiveRecord::ConnectionAdapters::Column.value_to_boolean(value)
end
0
mohamed-ibrahim

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.

0
chaimann