Ich sende einen Parameter show_all
mit dem Wert true
. Dieser Wert ist keinem Modell zugeordnet.
Mein Controller weist diesen Parameter einer Instanzvariablen zu:
@show_all = params[:show_all]
Jedoch @show_all.is_a? String
und if @show_all == true
scheitert immer.
Welche Werte analysiert Rails als Boolesche Werte? Wie kann ich explizit angeben, dass mein Parameter ein Boolescher Wert und kein String ist?
TrueClass
undFalseClass
TrueClass
oder behandeltFalseClass
. Irgendeine Idee, wie ich das gut machen kann?Antworten:
Ich wollte die zetetische Antwort kommentieren, aber da ich das noch nicht kann, werde ich dies als Antwort posten.
Wenn du benutzt
@show_all = params[:show_all] == "1"
Dann können Sie löschen,
? true : false
da dieparams[:show_all] == "1"
Anweisung selbst als wahr oder falsch ausgewertet wird und daher kein ternärer Operator benötigt wird.quelle
UPDATE: Rails 5:
ActiveRecord::Type::Boolean.new.deserialize('0')
UPDATE: Rails 4.2 hat eine öffentliche API dafür:
ActiveRecord::Type::Boolean.new.type_cast_from_user("0") # false
VORHERIGE ANTWORT:
ActiveRecord verwaltet eine Liste mit Darstellungen für true / false unter 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")
Dies ist nicht Teil der öffentlichen API von Rails, daher habe ich es in eine Hilfsmethode eingeschlossen:
class ApplicationController < ActionController::Base private def parse_boolean(value) ActiveRecord::ConnectionAdapters::Column.value_to_boolean(value) end end
und fügte einen Basistest hinzu:
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
quelle
ActiveRecord::Type::Boolean.new.type_cast_from_user("0")
zurückkehren wird ,false
wie Sie erwähnt, aber in Rails 5 wird es beginnen wahre Rückkehr: deprecation ACHTUNG: Sie haben versucht , einen Wert zuzuweisen , die nicht explizit isttrue
oderfalse
auf eine boolean Spalte. Derzeit wird dieser Wert auffalse
. Dies ändert sich entsprechend der Semantik von Ruby und wirdtrue
in Rails 5 umgewandelt. Wenn Sie das aktuelle Verhalten beibehalten möchten, sollten Sie die Werte, in die Sie umgewandelt werden möchten, explizit behandelnfalse
.ActiveRecord::Type::Boolean
ist nur ein Alias fürActiveModel::Type::Boolean
. Es ist wahrscheinlich ein kleines bisschen besser, die ursprüngliche Klasse zu verwenden.Diese Frage ist ziemlich alt, aber da ich ein paar Mal auf dieses Problem gestoßen bin und keine der vorgeschlagenen Lösungen mochte, habe ich selbst etwas gehackt, das es ermöglicht, mehrere Zeichenfolgen für wahr zu verwenden, z. B. "Ja", "Ein". , 't' und das Gegenteil für falsch.
Monkey patchen Sie die Klasse String und fügen Sie eine Methode hinzu, um sie in Boolesche Werte zu konvertieren. Fügen Sie diese Datei
/config/initializers
wie hier vorgeschlagen ein: Monkey Patching in Rails 3class 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
Beachten Sie, dass wenn der Wert weder für wahr noch für falsch einer der gültigen ist, nil zurückgegeben wird. Es ist nicht dasselbe zu suchen
?paid=false
(alle nicht bezahlten Datensätze zurückgeben) als?paid=
(Ich gebe nicht an, ob es bezahlt werden muss oder nicht - also verwerfen Sie dies).Wenn Sie dann diesem Beispiel folgen, sieht die Logik in Ihrem Controller folgendermaßen aus:
Something.where(:paid => params[:paid].to_bool) unless params[:paid].try(:to_bool).nil?
Es ist ziemlich ordentlich und hilft, Controller / Modelle sauber zu halten.
quelle
String#to_bool
, die zurückkehren kannnil
. Bitte meditieren Sie eine Weile darüber und benennen Sie die Methode dann entweder in so etwas umString#maybe_bool?
oder greifen Sie darauf zurückArgumentError
.def to_bool; ['true', '1', 'yes', 'on', 't'].include? self; end
TRUE_VALUES = ['true'.freeze, '1'.freeze, 'yes'.freeze, 'on'.freeze, 't'.freeze]
. Dies a) spart Speicher und b) verhindert Laufzeitänderungen der Strings.ActiveRecord::ConnectionAdapters::Column.value_to_boolean('')
zurückkehren wirdnil
.@show_all = params[:show_all] == "1" ? true : false
Dies sollte gut funktionieren, wenn Sie den Wert über ein Kontrollkästchen übergeben. Ein fehlender Schlüssel in einem Hash generiert null, was in einer Bedingung als falsch ausgewertet wird.
BEARBEITEN
Wie hier ausgeführt , ist der ternäre Operator nicht erforderlich, daher kann dies nur sein:
@show_all = params[:show_all] == "1"
quelle
Sie können Ihre Gleichstellungserklärung ändern in:
@show_all == "true"
Wenn Sie möchten, dass es sich um einen Booleschen Wert handelt, können Sie eine Methode für die Zeichenfolgenklasse erstellen, um eine Zeichenfolge in einen Booleschen Wert zu konvertieren.
quelle
Ich denke, die einfachste Lösung besteht darin, "boolesche" Parameter anhand ihrer String-Darstellung zu testen.
@show_all = params[:show_all] if @show_all.to_s == "true" # do stuff end
Unabhängig davon, ob Rails den Parameter als String "true" oder "false" oder als tatsächliche TrueClass oder FalseClass liefert, funktioniert dieser Test immer.
quelle
Ein anderer Ansatz besteht darin, nur den Schlüssel ohne Wert zu übergeben. Obwohl die Verwendung
ActiveRecord::Type::Boolean.new.type_cast_from_user(value)
ziemlich ordentlich ist, kann es vorkommen, dass das Zuweisen eines Werts zum Parameterschlüssel redundant ist.Beachten Sie Folgendes: In meiner Produktindexansicht möchte ich standardmäßig nur eine Sammlung von Produkten mit Gültigkeitsbereich anzeigen (z. B. diejenigen, die auf Lager sind). Wenn ich also alle Produkte zurückgeben möchte, kann ich
myapp.com/products?show_all=true
denshow_all
Parameter für einen booleschen Wert senden und typisieren .Die umgekehrte Option
myapp.com/products?show_all=false
macht jedoch keinen Sinn, da dieselbe Produktkollektion zurückgegeben wirdmyapp.com/products
, die zurückgegeben worden wäre.Eine Alternative:
Wenn ich die gesamte nicht gespeicherte Sammlung zurückgeben möchte, sende ich
myapp.com/products?all
und definiere in meinem Controllerprivate def show_all? params.key?(:all) end
Wenn der Schlüssel in params vorhanden ist, weiß ich unabhängig von seinem Wert, dass ich alle Produkte zurückgeben muss, ohne dass ein Wert typisiert werden muss.
quelle
Sie können Ihrem Modell Folgendes hinzufügen:
def show_all= value @show_all = ActiveRecord::ConnectionAdapters::Column.value_to_boolean(value) end
quelle
Du könntest es einfach tun
@show_all = params[:show_all].downcase == 'true'
quelle
Sie können alle Ihre booleschen Parameter wie folgt in echte Boolesche Werte konvertieren:
%w(show_all, show_featured).each do |bool_param| params[bool_param.to_sym] = params[bool_param.to_sym] == "true" end
In dieser Lösung würden keine Parameter falsch werden.
quelle
Es ist erwähnenswert, dass die einfachere Lösung darin besteht, einen Wert an ein ActiveModel in Rails> 5.2 zu übergeben
attribute
.class Model include ActiveModel::Attributes attribute :show_all, :boolean end Model.new(show_all: '0').show_all # => false
Wie hier zu sehen ist .
Vor 5.2 benutze ich:
class Model include ActiveModel::Attributes attribute_reader :show_all def show_all=(value) @show_all = ActiveModel::Type::Boolean.new.cast(value) end end Model.new(show_all: '0').show_all # => false
quelle