Skip to content

Commit

Permalink
active_record: Type cast booleans and durations for string columns.
Browse files Browse the repository at this point in the history
  • Loading branch information
dylanahsmith committed Jul 6, 2014
1 parent 93e24de commit 42be84b
Show file tree
Hide file tree
Showing 5 changed files with 49 additions and 5 deletions.
11 changes: 11 additions & 0 deletions activerecord/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,14 @@
* Avoid type casting boolean and ActiveSupport::Duration values to numeric
values for string columns. Otherwise, in some database, the string column
values will be coerced to a numeric allowing false or 0.seconds match any
string starting with a non-digit.

Example:

App.where(apikey: false) # => SELECT * FROM users WHERE apikey = '0'

*Dylan Thacker-Smith*

* Add a `:required` option to singular associations, providing a nicer
API for presence validations on associations.

Expand Down
2 changes: 1 addition & 1 deletion activerecord/lib/active_record/type/binary.rb
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ def type_cast_for_database(value)

class Data # :nodoc:
def initialize(value)
@value = value
@value = value.to_s
end

def to_s
Expand Down
4 changes: 3 additions & 1 deletion activerecord/lib/active_record/type/string.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,10 @@ def changed_in_place?(raw_old_value, new_value)

def type_cast_for_database(value)
case value
when ::Numeric then value.to_s
when ::Numeric, ActiveSupport::Duration then value.to_s
when ::String then ::String.new(value)
when true then "1"
when false then "0"
else super
end
end
Expand Down
4 changes: 2 additions & 2 deletions activerecord/test/cases/adapters/mysql2/boolean_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ class BooleanType < ActiveRecord::Base
assert_equal "1", attributes["published"]

assert_equal 1, @connection.type_cast(true, boolean_column)
assert_equal 1, @connection.type_cast(true, string_column)
assert_equal "1", @connection.type_cast(true, string_column)
end

test "test type casting without emulated booleans" do
Expand All @@ -60,7 +60,7 @@ class BooleanType < ActiveRecord::Base
assert_equal "1", attributes["published"]

assert_equal 1, @connection.type_cast(true, boolean_column)
assert_equal 1, @connection.type_cast(true, string_column)
assert_equal "1", @connection.type_cast(true, string_column)
end

test "with booleans stored as 1 and 0" do
Expand Down
33 changes: 32 additions & 1 deletion activerecord/test/cases/relation/where_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@
require 'models/comment'
require 'models/edge'
require 'models/topic'
require 'models/binary'

module ActiveRecord
class WhereTest < ActiveRecord::TestCase
fixtures :posts, :edges, :authors
fixtures :posts, :edges, :authors, :binaries

def test_where_copies_bind_params
author = authors(:david)
Expand Down Expand Up @@ -179,5 +180,35 @@ def test_where_with_blank_conditions
assert_equal 4, Edge.where(blank).order("sink_id").to_a.size
end
end

def test_where_with_integer_for_string_column
count = Post.where(:title => 0).count
assert_equal 0, count
end

def test_where_with_float_for_string_column
count = Post.where(:title => 0.0).count
assert_equal 0, count
end

def test_where_with_boolean_for_string_column
count = Post.where(:title => false).count
assert_equal 0, count
end

def test_where_with_decimal_for_string_column
count = Post.where(:title => BigDecimal.new(0)).count
assert_equal 0, count
end

def test_where_with_duration_for_string_column
count = Post.where(:title => 0.seconds).count
assert_equal 0, count
end

def test_where_with_integer_for_binary_column
count = Binary.where(:data => 0).count
assert_equal 0, count
end
end
end

0 comments on commit 42be84b

Please sign in to comment.