Mam aplikację Rails i używam jQuery do odpytywania mojego widoku wyszukiwania w tle. Istnieją pola q
(wyszukiwane hasło) start_date
, end_date
i internal
. To internal
pole jest polem wyboru i używam is(:checked)
metody do budowania adresu URL, który jest odpytywany:
$.getScript(document.URL + "?q=" + $("#search_q").val() + "&start_date=" + $("#search_start_date").val() + "&end_date=" + $("#search_end_date").val() + "&internal=" + $("#search_internal").is(':checked'));
Teraz mój problem tkwi w tym, params[:internal]
że istnieje łańcuch zawierający „prawda” lub „fałsz” i muszę go rzutować na wartość logiczną. Oczywiście mogę to zrobić w ten sposób:
def to_boolean(str)
return true if str=="true"
return false if str=="false"
return nil
end
Ale myślę, że musi istnieć bardziej Rubinowy sposób rozwiązania tego problemu! Czy nie ma ...?
jquery
ruby-on-rails
ruby
ruby-on-rails-3
davidb
źródło
źródło
ActiveRecord zapewnia przejrzysty sposób na zrobienie tego.
def is_true?(string) ActiveRecord::ConnectionAdapters::Column::TRUE_VALUES.include?(string) end
ActiveRecord::ConnectionAdapters::Column::TRUE_VALUES
ma wszystkie oczywiste reprezentacje wartości True jako łańcuchy.źródło
ActiveRecord::ConnectionAdapters::Column.value_to_boolean(string)
(źródło) apidock.com/rails/v3.0.9/ActiveRecord/ConnectionAdapters/Column/ ...ActiveRecord::Type::Boolean.new.type_cast_from_user("true")
=> trueActiveRecord::Type::Boolean.new.type_cast_from_user("T")
=> trueActiveModel::Type::Boolean
wydaje się o wiele bardziej odpowiednią ścieżką - chociażActiveRecord::ConnectionAdapters::Column::TRUE_VALUES
zawierały „prawdziwe” wartości, można by argumentować, że jest to przypadek i że wartości, które powinny być uznane za prawdziwe w tym konkretnym przypadku użycia, ale nie mogą być uwzględnione. Z drugiej stronyActiveModel::Type::Boolean
jest najwyraźniej zaprojektowany do użytku w sposób ogólny.Uwaga dotycząca bezpieczeństwa
Zwróć uwagę, że ta odpowiedź w czystej postaci jest odpowiednia tylko dla innego przypadku użycia wymienionego poniżej, a nie tego w pytaniu. Chociaż w większości naprawiono, pojawiło się wiele luk w zabezpieczeniach związanych z YAML, które były spowodowane ładowaniem danych wejściowych użytkownika jako YAML.
Sztuczka, której używam do konwersji ciągów znaków na bools, to na
YAML.load
przykład:YAML.load(var) # -> true/false if it's one of the below
YAML bool akceptuje całkiem sporo prawdziwych / fałszywych ciągów:
y|Y|yes|Yes|YES|n|N|no|No|NO |true|True|TRUE|false|False|FALSE |on|On|ON|off|Off|OFF
Inny przypadek użycia
Załóżmy, że masz taki fragment kodu konfiguracyjnego:
config.etc.something = ENV['ETC_SOMETHING']
A w linii poleceń:
$ export ETC_SOMETHING=false
Ponieważ
ENV
zmienne są ciągami znaków znajdującymi się w kodzie,config.etc.something
wartość byłaby łańcuchem"false"
i byłaby niepoprawnie obliczana dotrue
. Ale jeśli podoba ci się to:config.etc.something = YAML.load(ENV['ETC_SOMETHING'])
wszystko byłoby w porządku. Jest to również zgodne z ładowaniem konfiguracji z plików .yml.
źródło
Nie ma żadnego wbudowanego sposobu, aby sobie z tym poradzić (chociaż pakiet akcji może mieć do tego pomocnika). Radziłbym coś takiego
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
Co również działa, to użycie 0 i wartości różnej od 0 zamiast fałszywych / prawdziwych literałów:
def to_boolean(s) !s.to_i.zero? end
źródło
.match
jest trochę łatwiejszy do odczytania.ActiveRecord::Type::Boolean.new.type_cast_from_user
robi to zgodnie z wewnętrznym mapowaniem RailsówConnectionAdapters::Column::TRUE_VALUES
iConnectionAdapters::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
Możesz więc stworzyć własną
to_b
(lubto_bool
lubto_boolean
) metodę w inicjatorze takim jak ten:class String def to_b ActiveRecord::Type::Boolean.new.type_cast_from_user(self) end end
źródło
Możesz użyć gem wannabe_bool. https://github.com/prodis/wannabe_bool
Ten klejnot implementuje
#to_b
metodę dla klas String, Integer, Symbol i NilClass.params[:internal].to_b
źródło
W Rails 5 możesz użyć
ActiveRecord::Type::Boolean.new.cast(value)
do rzutowania go na wartość logiczną.źródło
Nie sądzę, żeby coś takiego było wbudowane w Ruby. Możesz ponownie otworzyć klasę String i dodać tam metodę to_bool:
class String def to_bool return true if self=="true" return false if self=="false" return nil end end
Następnie możesz go użyć w dowolnym miejscu w swoim projekcie, na przykład:
params[:internal].to_bool
źródło
to_bool
powrotu funkcjinil
; to wydaje się złe. Inne funkcje konwersji tego nie robią:"a".to_i
zwraca0
, nienil
Może
str.to_s.downcase == 'true'
dla kompletności. Wtedy nic nie może się zawiesić, nawet jeślistr
wynosi zero lub 0.źródło
Patrząc na kod źródłowy Virtusa , może zrobiłbym coś takiego:
def to_boolean(s) map = Hash[%w[true yes 1].product([true]) + %w[false no 0].product([false])] map[s.to_s.downcase] end
źródło
Możesz rozważyć dołączenie
internal
do swojego adresu URL tylko wtedy, gdy jest prawdziwe, a wtedy, jeśli pole wyboru nie jest zaznaczone i nie zostanie dołączone,params[:internal]
będzie to oznaczaćnil
wartość false w Rubim.Nie jestem zaznajomiony z konkretnym jQuery, którego używasz, ale czy istnieje bardziej przejrzysty sposób wywoływania tego, co chcesz, niż ręczne tworzenie ciągu adresu URL? Czy spojrzałeś na
$get
i$ajax
?źródło
Możesz dodać do klasy String, aby uzyskać metodę to_boolean. Następnie możesz zrobić „true ”.to_boolean lub„ 1 ”.to_boolean
class String def to_boolean self == 'true' || self == '1' end end
źródło
Dziwię się, że nikt nie opublikował tego prostego rozwiązania. To znaczy, jeśli twoje łańcuchy będą „prawdziwe” lub „fałszywe”.
def to_boolean(str) eval(str) end
źródło
to_boolean("ActiveRecord::Base.connection.execute('DROP TABLE *')")
, zniszczy to twoją bazę danych (i zwróci true!). Baw się dobrze: Dbool = nil; bool = eval(str) if ["true", "false"].include?(str)
pomyślałem, że powinienem dodać w celu wyjaśnienia.