web-dev-qa-db-fra.com

Chaîne "true" et "false" en booléen

J'ai une application Rails et j'utilise jQuery pour interroger ma vue de recherche en arrière-plan. Il existe des champs q (terme de recherche), start_date, end_date Et internal. Le champ internal est une case à cocher et j'utilise la méthode is(:checked) pour construire l'URL interrogée:

$.getScript(document.URL + "?q=" + $("#search_q").val() + "&start_date=" + $("#search_start_date").val() + "&end_date=" + $("#search_end_date").val() + "&internal=" + $("#search_internal").is(':checked'));

Maintenant, mon problème est dans params[:internal] Car il y a une chaîne contenant "true" ou "false" et je dois la convertir en booléen. Bien sûr, je peux le faire comme ça:

def to_boolean(str)
     return true if str=="true"
     return false if str=="false"
     return nil
end

Mais je pense qu'il doit y avoir un moyen plus rubyish de traiter ce problème! N'y a-t-il pas ...?

82
davidb

Autant que je sache, il n’existe pas de méthode intégrée pour transformer des chaînes en booléens, mais si vos chaînes ne sont constituées que de 'true' et 'false' vous pouvez raccourcir votre méthode comme suit:

def to_boolean(str)
  str == 'true'
end
129
cvshepherd

ActiveRecord fournit un moyen propre de le faire.

def is_true?(string)
  ActiveRecord::ConnectionAdapters::Column::TRUE_VALUES.include?(string)
end

ActiveRecord::ConnectionAdapters::Column::TRUE_VALUES présente toutes les représentations évidentes des valeurs vraies sous forme de chaînes.

47
Satya Kalluri

Avis de sécurité

Notez que cette réponse sous sa forme nue ne convient que pour l'autre cas d'utilisation répertorié ci-dessous plutôt que pour celui de la question. Bien que la plupart des problèmes aient été résolus, il y a eu de nombreuses vulnérabilités de sécurité liées à YAML qui ont été causées par le chargement d'une entrée utilisateur au format YAML.


Un truc que j’utilise pour convertir des chaînes en bools est YAML.load , par exemple:

YAML.load(var) # -> true/false if it's one of the below

YAML bool accepte pas mal de chaînes vérité/fausseté:

y|Y|yes|Yes|YES|n|N|no|No|NO
|true|True|TRUE|false|False|FALSE
|on|On|ON|off|Off|OFF

Un autre cas d'utilisation

Supposons que vous ayez un morceau de code de configuration comme ceci:

config.etc.something = ENV['ETC_SOMETHING']

Et en ligne de commande:

$ export ETC_SOMETHING=false

Maintenant, puisque ENVvars sont des chaînes une fois insérées dans le code, la valeur de config.etc.something Serait la chaîne "false" Et serait évaluée incorrectement à true. Mais si vous aimez ça:

config.etc.something = YAML.load(ENV['ETC_SOMETHING'])

tout irait bien. Ceci est également compatible avec le chargement de configurations à partir de fichiers .yml.

23
Halil Özgür

Il n'y a pas de moyen intégré pour gérer cela (bien que actionpack puisse avoir un assistant pour cela). Je conseillerais quelque chose comme ça

def to_boolean(s)
  s and !!s.match(/^(true|t|yes|y|1)$/i)
end

# or (as Pavling pointed out)

def to_boolean(s)
  !!(s =~ /^(true|t|yes|y|1)$/i)
end

Ce qui fonctionne aussi est d’utiliser 0 et non-0 au lieu de littéraux faux/vrais:

def to_boolean(s)
  !s.to_i.zero?
end
16
Marcel Jackwerth

ActiveRecord::Type::Boolean.new.type_cast_from_user fait cela en fonction des correspondances internes de Rails ConnectionAdapters::Column::TRUE_VALUES et ConnectionAdapters::Column::FALSE_VALUES:

[3] pry(main)> ActiveRecord::Type::Boolean.new.type_cast_from_user("true")
=> true
[4] pry(main)> ActiveRecord::Type::Boolean.new.type_cast_from_user("false")
=> false
[5] pry(main)> ActiveRecord::Type::Boolean.new.type_cast_from_user("T")
=> true
[6] pry(main)> ActiveRecord::Type::Boolean.new.type_cast_from_user("F")
=> false
[7] pry(main)> ActiveRecord::Type::Boolean.new.type_cast_from_user("yes")
DEPRECATION WARNING: You attempted to assign a value which is not explicitly `true` or `false` ("yes") to a boolean column. Currently this value casts to `false`. This will change to match Ruby's semantics, and will cast to `true` in Rails 5. If you would like to maintain the current behavior, you should explicitly handle the values you would like cast to `false`. (called from <main> at (pry):7)
=> false
[8] pry(main)> ActiveRecord::Type::Boolean.new.type_cast_from_user("no")
DEPRECATION WARNING: You attempted to assign a value which is not explicitly `true` or `false` ("no") to a boolean column. Currently this value casts to `false`. This will change to match Ruby's semantics, and will cast to `true` in Rails 5. If you would like to maintain the current behavior, you should explicitly handle the values you would like cast to `false`. (called from <main> at (pry):8)
=> false

Pour que vous puissiez faire votre propre to_b (ou to_bool ou to_boolean) dans un initialiseur comme ceci:

class String
  def to_b
    ActiveRecord::Type::Boolean.new.type_cast_from_user(self)
  end
end
7
AlexChaffee

Dans Rails 5, vous pouvez utiliser ActiveRecord::Type::Boolean.new.cast(value)] pour le convertir en un booléen.

5
CWitty

Vous pouvez utiliser wannabe_bool gem. https://github.com/prodis/wannabe_bool

Ce bijou implémente un #to_b Méthode pour les classes String, Integer, Symbol et NilClass.

params[:internal].to_b
5
Prodis

Je ne pense pas que quelque chose comme ça soit intégré à Ruby. Vous pouvez rouvrir la classe String et ajouter la méthode to_bool à cet endroit:

class String
    def to_bool
        return true if self=="true"
        return false if self=="false"
        return nil
    end
end

Ensuite, vous pouvez l’utiliser n'importe où dans votre projet, comme ceci: params[:internal].to_bool

3
socha23

Peut-être que str.to_s.downcase == 'true' pour être complet. Alors rien ne peut planter même si str est nul ou 0.

3
user1839842

En regardant le code source de Virtus , je ferais peut-être quelque chose comme ceci:

def to_boolean(s)
  map = Hash[%w[true yes 1].product([true]) + %w[false no 0].product([false])]
  map[s.to_s.downcase]
end
2
d11wtq

Vous pouvez ajouter à la classe String la méthode de to_boolean. Ensuite, vous pouvez faire 'true'. To_boolean ou '1'. to_boolean

class String
  def to_boolean
    self == 'true' || self == '1'
  end
end
1
Josh Cavin

Vous pouvez envisager d'ajouter uniquement internal à votre URL si elle est vraie. Si la case n'est pas cochée et que vous ne l'ajoutez pas, params[:internal] Équivaut à nil, est évalué à faux en Ruby.

Je ne connais pas très bien jQuery que vous utilisez, mais existe-t-il un moyen plus simple d'appeler ce que vous voulez plutôt que de créer manuellement une chaîne d'URL? Avez-vous jeté un œil à $get Et à $ajax?

1
Russell