提交 2d12f800 编写于 作者: R Ryuta Kamizono

Type cast falsy boolean symbols on boolean attribute as false

Before 34cc301f, type casting by boolean attribute when querying is a
no-op, so finding by truthy boolean string (i.e.
`where(value: "true") # => value = 'true'`) didn't work as expected
(matches it to FALSE in MySQL #32624). By type casting is ensured, a
value on boolean attribute is always serialized to TRUE or FALSE.

In PostgreSQL, `where(value: :false) # => value = 'false'` was a valid
SQL, so 34cc301f is a regresson for PostgreSQL since all symbol values
are serialized as TRUE.

I'd say using `:false` is mostly a developer's mistake (user's input
basically comes as a string), but `:false` on boolean attribute is
serialized as TRUE is not a desirable behavior for anybody.

This allows falsy boolean symbols as false, i.e.
`klass.create(value: :false).value? # => false` and
`where(value: :false) # => value = FALSE`.

Fixes #35676.
上级 da2c9237
* Type cast falsy boolean symbols on boolean attribute as false.
Fixes #35676.
*Ryuta Kamizono*
* Change how validation error translation strings are fetched: The new behavior
will first try the more specific keys, including doing locale fallback, then try
the less specific ones.
......
......@@ -14,7 +14,16 @@ module Type
# - Empty strings are coerced to +nil+
# - All other values will be coerced to +true+
class Boolean < Value
FALSE_VALUES = [false, 0, "0", "f", "F", "false", "FALSE", "off", "OFF"].to_set
FALSE_VALUES = [
false, 0,
"0", :"0",
"f", :f,
"F", :F,
"false", :false,
"FALSE", :FALSE,
"off", :off,
"OFF", :OFF,
].to_set.freeze
def type # :nodoc:
:boolean
......
......@@ -23,6 +23,13 @@ def test_type_cast_boolean
assert type.cast("\u3000\r\n")
assert type.cast("\u0000")
assert type.cast("SOMETHING RANDOM")
assert type.cast(:"1")
assert type.cast(:t)
assert type.cast(:T)
assert type.cast(:true)
assert type.cast(:TRUE)
assert type.cast(:on)
assert type.cast(:ON)
# explicitly check for false vs nil
assert_equal false, type.cast(false)
......@@ -34,6 +41,13 @@ def test_type_cast_boolean
assert_equal false, type.cast("FALSE")
assert_equal false, type.cast("off")
assert_equal false, type.cast("OFF")
assert_equal false, type.cast(:"0")
assert_equal false, type.cast(:f)
assert_equal false, type.cast(:F)
assert_equal false, type.cast(:false)
assert_equal false, type.cast(:FALSE)
assert_equal false, type.cast(:off)
assert_equal false, type.cast(:OFF)
end
end
end
......
......@@ -40,4 +40,13 @@ def test_find_by_boolean_string
assert_equal b_false, Boolean.find_by(value: "false")
assert_equal b_true, Boolean.find_by(value: "true")
end
def test_find_by_falsy_boolean_symbol
ActiveModel::Type::Boolean::FALSE_VALUES.each do |value|
b_false = Boolean.create!(value: value)
assert_not_predicate b_false, :value?
assert_equal b_false, Boolean.find_by(id: b_false.id, value: value.to_s.to_sym)
end
end
end
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册