formtastic_tristate_radio
Скачен 5 374 раза
Что оно делает
- Provides a custom Formtastic input type :tristate_radio which renders 3 radios (“Yes”, “No”, “Unset”) instead of a checkbox (only where you put it).
- Teaches Rails recognize "null" and "nil" param values as nil. See “How it works” ☟ section for technical details on this.
- Encourages you to add translations for ActiveAdmin “status tag” so that nil be correctly translated as “Unset” instead of “False”.
Как оно это делает
In Ruby any String is cast to true:
!!"" #=> true
!!"false" #=> true
!!"nil" #=> true
!!"no" #=> true
!!"null" #=> true
Web form params are passed as plain text and are interpreted as String by Rack.
So how Boolean values are transfered as strings if a "no" or "0" and even "" is truthy in Ruby?
Frameworks just have a list of string values to be recognized and mapped to Boolean values:
ActiveModel::Type::Boolean::FALSE_VALUES
#=> [
0, "0", :"0",
"f", :f, "F", :F,
false, "false", :false, "FALSE", :FALSE,
"off", :off, "OFF", :OFF,
]
so that
ActiveModel::Type::Boolean.new.cast("0") #=> false
ActiveModel::Type::Boolean.new.cast("f") #=> false
ActiveModel::Type::Boolean.new.cast(:FALSE) #=> false
ActiveModel::Type::Boolean.new.cast("off") #=> false
# etc
So what I do in this gem is extend ActiveModel::Type::Boolean in a consistent way to teach it recognize null-ish values as nil:
module ActiveModel
module Type
class Boolean < Value
NULL_VALUES = [nil, "", "null", :null, "nil", :nil].to_set.freeze
private def cast_value(value)
NULL_VALUES.include?(value) ? nil : !FALSE_VALUES.include?(value)
end
end
end
end
And voila!
ActiveModel::Type::Boolean.new.cast("") #=> nil
ActiveModel::Type::Boolean.new.cast("null") #=> nil
ActiveModel::Type::Boolean.new.cast(:null) #=> nil
ActiveModel::Type::Boolean.new.cast("nil") #=> nil
ActiveModel::Type::Boolean.new.cast(:nil) #=> nil
Warning: as you might have noticed, default Rails behavior is changed. If you rely on Rails’ automatic conversion of strings with value "null" into true, this gem might not be for you (and you are definitely doing something weird).