提交 52c3a16f 编写于 作者: S Sean Griffin

Revert the behavior of booleans in string columns to that of 4.1

Why are people assigning booleans to string columns? >_>

We unintentionally changed the behavior on Sqlite3 and PostgreSQL.
Boolean values should cast to the database's representation of true and
false. This is 't' and 'f' by default, and "1" and "0" on Mysql. The
implementation to make the connection adapter specific behavior is hacky
at best, and should be re-visted once we decide how we actually want to
separate the concerns related to things that should change based on the
database adapter.

That said, this isn't something I'd expect to change based on my
database adapter. We're storing a string, so the way the database
represents a boolean should be irrelevant. It also seems strange for us
to give booleans special behavior at all in string columns. Why is
`to_s` not sufficient? It's inconsistent and confusing. Perhaps we
should consider deprecating in the future.

Fixes #17571
上级 cb0ba2f2
...@@ -648,6 +648,8 @@ def valid_type?(type) ...@@ -648,6 +648,8 @@ def valid_type?(type)
def initialize_type_map(m) # :nodoc: def initialize_type_map(m) # :nodoc:
super super
register_class_with_limit m, %r(char)i, MysqlString
m.register_type %r(tinytext)i, Type::Text.new(limit: 2**8 - 1) m.register_type %r(tinytext)i, Type::Text.new(limit: 2**8 - 1)
m.register_type %r(tinyblob)i, Type::Binary.new(limit: 2**8 - 1) m.register_type %r(tinyblob)i, Type::Binary.new(limit: 2**8 - 1)
m.register_type %r(text)i, Type::Text.new(limit: 2**16 - 1) m.register_type %r(text)i, Type::Text.new(limit: 2**16 - 1)
...@@ -672,7 +674,7 @@ def initialize_type_map(m) # :nodoc: ...@@ -672,7 +674,7 @@ def initialize_type_map(m) # :nodoc:
m.register_type(%r(enum)i) do |sql_type| m.register_type(%r(enum)i) do |sql_type|
limit = sql_type[/^enum\((.+)\)/i, 1] limit = sql_type[/^enum\((.+)\)/i, 1]
.split(',').map{|enum| enum.strip.length - 2}.max .split(',').map{|enum| enum.strip.length - 2}.max
Type::String.new(limit: limit) MysqlString.new(limit: limit)
end end
end end
...@@ -847,6 +849,26 @@ def extract_foreign_key_action(structure, name, action) # :nodoc: ...@@ -847,6 +849,26 @@ def extract_foreign_key_action(structure, name, action) # :nodoc:
end end
end end
end end
class MysqlString < Type::String # :nodoc:
def type_cast_for_database(value)
case value
when true then "1"
when false then "0"
else super
end
end
private
def cast_value(value)
case value
when true then "1"
when false then "0"
else super
end
end
end
end end
end end
end end
...@@ -15,8 +15,8 @@ def type_cast_for_database(value) ...@@ -15,8 +15,8 @@ def type_cast_for_database(value)
case value case value
when ::Numeric, ActiveSupport::Duration then value.to_s when ::Numeric, ActiveSupport::Duration then value.to_s
when ::String then ::String.new(value) when ::String then ::String.new(value)
when true then "1" when true then "t"
when false then "0" when false then "f"
else super else super
end end
end end
...@@ -25,8 +25,8 @@ def type_cast_for_database(value) ...@@ -25,8 +25,8 @@ def type_cast_for_database(value)
def cast_value(value) def cast_value(value)
case value case value
when true then "1" when true then "t"
when false then "0" when false then "f"
# String.new is slightly faster than dup # String.new is slightly faster than dup
else ::String.new(value.to_s) else ::String.new(value.to_s)
end end
......
...@@ -4,8 +4,8 @@ module ActiveRecord ...@@ -4,8 +4,8 @@ module ActiveRecord
class StringTypeTest < ActiveRecord::TestCase class StringTypeTest < ActiveRecord::TestCase
test "type casting" do test "type casting" do
type = Type::String.new type = Type::String.new
assert_equal "1", type.type_cast_from_user(true) assert_equal "t", type.type_cast_from_user(true)
assert_equal "0", type.type_cast_from_user(false) assert_equal "f", type.type_cast_from_user(false)
assert_equal "123", type.type_cast_from_user(123) assert_equal "123", type.type_cast_from_user(123)
end end
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册