aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord
diff options
context:
space:
mode:
Diffstat (limited to 'activerecord')
-rw-r--r--activerecord/CHANGELOG.md20
-rw-r--r--activerecord/lib/active_record/attribute_set.rb12
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/cast.rb43
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/oid/float.rb1
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/oid/hstore.rb36
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb28
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb2
-rw-r--r--activerecord/lib/active_record/core.rb8
-rw-r--r--activerecord/lib/active_record/counter_cache.rb2
-rw-r--r--activerecord/lib/active_record/inheritance.rb8
-rw-r--r--activerecord/lib/active_record/migration.rb13
-rw-r--r--activerecord/lib/active_record/persistence.rb1
-rw-r--r--activerecord/lib/active_record/relation/calculations.rb2
-rw-r--r--activerecord/lib/active_record/tasks/database_tasks.rb2
-rw-r--r--activerecord/lib/active_record/tasks/sqlite_database_tasks.rb6
-rw-r--r--activerecord/lib/active_record/type/string.rb8
-rw-r--r--activerecord/test/cases/adapters/postgresql/hstore_test.rb16
-rw-r--r--activerecord/test/cases/adapters/postgresql/infinity_test.rb44
-rw-r--r--activerecord/test/cases/adapters/postgresql/money_test.rb24
-rw-r--r--activerecord/test/cases/adapters/postgresql/quoting_test.rb11
-rw-r--r--activerecord/test/cases/adapters/postgresql/range_test.rb17
-rw-r--r--activerecord/test/cases/counter_cache_test.rb10
-rw-r--r--activerecord/test/cases/dup_test.rb12
-rw-r--r--activerecord/test/cases/migration/pending_migrations_test.rb7
-rw-r--r--activerecord/test/cases/persistence_test.rb12
-rw-r--r--activerecord/test/cases/reflection_test.rb32
26 files changed, 260 insertions, 117 deletions
diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md
index 7e40373163..83510c40c8 100644
--- a/activerecord/CHANGELOG.md
+++ b/activerecord/CHANGELOG.md
@@ -1,3 +1,14 @@
+* Fixed error in `reset_counters` when associations have `select` scope.
+ (Call to `count` generates invalid SQL.)
+
+ *Cade Truitt*
+
+* After a successful `reload`, `new_record?` is always false.
+
+ Fixes #12101.
+
+ *Matthew Draper*
+
* PostgreSQL renaming table doesn't attempt to rename non existent sequences.
*Abdelkader Boudih*
@@ -128,14 +139,7 @@
Serialized attributes on ActiveRecord models will no longer save when
unchanged. Fixes #8328.
- Sean Griffin
-
-* Fixed automatic maintaining test schema to properly handle sql structure
- schema format.
-
- Fixes #15394.
-
- *Wojciech Wnętrzak*
+ *Sean Griffin*
* Pluck now works when selecting columns from different tables with the same
name.
diff --git a/activerecord/lib/active_record/attribute_set.rb b/activerecord/lib/active_record/attribute_set.rb
index 8a964fb03c..64df6f6358 100644
--- a/activerecord/lib/active_record/attribute_set.rb
+++ b/activerecord/lib/active_record/attribute_set.rb
@@ -52,6 +52,18 @@ module ActiveRecord
super
end
+ def reset(key)
+ if include?(key)
+ write_from_database(key, nil)
+ end
+ end
+
+ def ensure_initialized(key)
+ unless self[key].initialized?
+ write_from_database(key, nil)
+ end
+ end
+
protected
attr_reader :attributes
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/cast.rb b/activerecord/lib/active_record/connection_adapters/postgresql/cast.rb
index c916c0795d..5b3e88fb08 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/cast.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/cast.rb
@@ -2,54 +2,11 @@ module ActiveRecord
module ConnectionAdapters
module PostgreSQL
module Cast # :nodoc:
- def hstore_to_string(object) # :nodoc:
- if Hash === object
- string = object.map { |k, v| "#{escape_hstore(k)}=>#{escape_hstore(v)}" }.join(', ')
- string
- else
- object
- end
- end
-
- def string_to_hstore(string) # :nodoc:
- if string.nil?
- nil
- elsif String === string
- Hash[string.scan(HstorePair).map { |k, v|
- v = v.upcase == 'NULL' ? nil : v.gsub(/\A"(.*)"\Z/m,'\1').gsub(/\\(.)/, '\1')
- k = k.gsub(/\A"(.*)"\Z/m,'\1').gsub(/\\(.)/, '\1')
- [k, v]
- }]
- else
- string
- end
- end
-
def range_to_string(object) # :nodoc:
from = object.begin.respond_to?(:infinite?) && object.begin.infinite? ? '' : object.begin
to = object.end.respond_to?(:infinite?) && object.end.infinite? ? '' : object.end
"[#{from},#{to}#{object.exclude_end? ? ')' : ']'}"
end
-
- private
-
- HstorePair = begin
- quoted_string = /"[^"\\]*(?:\\.[^"\\]*)*"/
- unquoted_string = /(?:\\.|[^\s,])[^\s=,\\]*(?:\\.[^\s=,\\]*|=[^,>])*/
- /(#{quoted_string}|#{unquoted_string})\s*=>\s*(#{quoted_string}|#{unquoted_string})/
- end
-
- def escape_hstore(value)
- if value.nil?
- 'NULL'
- else
- if value == ""
- '""'
- else
- '"%s"' % value.to_s.gsub(/(["\\])/, '\\\\\1')
- end
- end
- end
end
end
end
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/oid/float.rb b/activerecord/lib/active_record/connection_adapters/postgresql/oid/float.rb
index 26c5d3d78f..78ef94b912 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/oid/float.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/oid/float.rb
@@ -7,6 +7,7 @@ module ActiveRecord
def cast_value(value)
case value
+ when ::Float then value
when 'Infinity' then ::Float::INFINITY
when '-Infinity' then -::Float::INFINITY
when 'NaN' then ::Float::NAN
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/oid/hstore.rb b/activerecord/lib/active_record/connection_adapters/postgresql/oid/hstore.rb
index 57b20477df..be4525c94f 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/oid/hstore.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/oid/hstore.rb
@@ -10,16 +10,48 @@ module ActiveRecord
end
def type_cast_from_database(value)
- ConnectionAdapters::PostgreSQLColumn.string_to_hstore(value)
+ if value.is_a?(::String)
+ ::Hash[value.scan(HstorePair).map { |k, v|
+ v = v.upcase == 'NULL' ? nil : v.gsub(/\A"(.*)"\Z/m,'\1').gsub(/\\(.)/, '\1')
+ k = k.gsub(/\A"(.*)"\Z/m,'\1').gsub(/\\(.)/, '\1')
+ [k, v]
+ }]
+ else
+ value
+ end
end
def type_cast_for_database(value)
- ConnectionAdapters::PostgreSQLColumn.hstore_to_string(value)
+ if value.is_a?(::Hash)
+ value.map { |k, v| "#{escape_hstore(k)}=>#{escape_hstore(v)}" }.join(', ')
+ else
+ value
+ end
end
def accessor
ActiveRecord::Store::StringKeyedHashAccessor
end
+
+ private
+
+ HstorePair = begin
+ quoted_string = /"[^"\\]*(?:\\.[^"\\]*)*"/
+ unquoted_string = /(?:\\.|[^\s,])[^\s=,\\]*(?:\\.[^\s=,\\]*|=[^,>])*/
+ /(#{quoted_string}|#{unquoted_string})\s*=>\s*(#{quoted_string}|#{unquoted_string})/
+ end
+
+ def escape_hstore(value)
+ if value.nil?
+ 'NULL'
+ else
+ if value == ""
+ '""'
+ else
+ '"%s"' % value.to_s.gsub(/(["\\])/, '\\\\\1')
+ end
+ end
+ end
end
end
end
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb b/activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb
index f9541b437a..39b36731cd 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb
@@ -23,37 +23,24 @@ module ActiveRecord
case value
when Range
if /range$/ =~ sql_type
- "'#{PostgreSQLColumn.range_to_string(value)}'::#{sql_type}"
+ escaped = quote_string(PostgreSQLColumn.range_to_string(value))
+ "'#{escaped}'::#{sql_type}"
else
super
end
- when Hash
- case sql_type
- when 'hstore' then super(PostgreSQLColumn.hstore_to_string(value), column)
- else super
- end
when Float
- if value.infinite? && column.type == :datetime
- "'#{value.to_s.downcase}'"
- elsif value.infinite? || value.nan?
+ if value.infinite? || value.nan?
"'#{value.to_s}'"
else
super
end
- when Numeric
- if sql_type == 'money' || [:string, :text].include?(column.type)
- # Not truly string input, so doesn't require (or allow) escape string syntax.
- "'#{value}'"
- else
- super
- end
when String
case sql_type
when 'xml' then "xml '#{quote_string(value)}'"
when /^bit/
case value
- when /^[01]*$/ then "B'#{value}'" # Bit-string notation
- when /^[0-9A-F]*$/i then "X'#{value}'" # Hexadecimal notation
+ when /\A[01]*\Z/ then "B'#{value}'" # Bit-string notation
+ when /\A[0-9A-F]*\Z/i then "X'#{value}'" # Hexadecimal notation
end
else
super
@@ -79,11 +66,6 @@ module ActiveRecord
else
super
end
- when Hash
- case column.sql_type
- when 'hstore' then PostgreSQLColumn.hstore_to_string(value)
- else super
- end
else
super
end
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
index a164758640..8e31e165b1 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
@@ -569,7 +569,7 @@ module ActiveRecord
end
def exec_no_cache(sql, name, binds)
- log(sql, name, binds) { @connection.async_exec(sql) }
+ log(sql, name, binds) { @connection.async_exec(sql, []) }
end
def exec_cache(sql, name, binds)
diff --git a/activerecord/lib/active_record/core.rb b/activerecord/lib/active_record/core.rb
index 224112b559..b11c4f804f 100644
--- a/activerecord/lib/active_record/core.rb
+++ b/activerecord/lib/active_record/core.rb
@@ -315,9 +315,8 @@ module ActiveRecord
##
def initialize_dup(other) # :nodoc:
- pk = self.class.primary_key
@attributes = @attributes.dup
- @attributes.write_from_database(pk, nil)
+ @attributes.reset(self.class.primary_key)
run_callbacks(:initialize) unless _initialize_callbacks.empty?
@@ -515,10 +514,7 @@ module ActiveRecord
end
def init_internals
- pk = self.class.primary_key
- if pk && !@attributes.include?(pk)
- @attributes.write_from_database(pk, nil)
- end
+ @attributes.ensure_initialized(self.class.primary_key)
@aggregation_cache = {}
@association_cache = {}
diff --git a/activerecord/lib/active_record/counter_cache.rb b/activerecord/lib/active_record/counter_cache.rb
index 05c4b13016..a33c7c64a7 100644
--- a/activerecord/lib/active_record/counter_cache.rb
+++ b/activerecord/lib/active_record/counter_cache.rb
@@ -38,7 +38,7 @@ module ActiveRecord
counter_name = reflection.counter_cache_column
stmt = unscoped.where(arel_table[primary_key].eq(object.id)).arel.compile_update({
- arel_table[counter_name] => object.send(counter_association).count
+ arel_table[counter_name] => object.send(counter_association).count(:all)
}, primary_key)
connection.update stmt
end
diff --git a/activerecord/lib/active_record/inheritance.rb b/activerecord/lib/active_record/inheritance.rb
index 5c2f1215d2..f6c265a6d6 100644
--- a/activerecord/lib/active_record/inheritance.rb
+++ b/activerecord/lib/active_record/inheritance.rb
@@ -16,14 +16,14 @@ module ActiveRecord
# the companies table with type = "Firm". You can then fetch this row again using
# <tt>Company.where(name: '37signals').first</tt> and it will return a Firm object.
#
- # Be aware that because the type column is an attribute on the record every new
+ # Be aware that because the type column is an attribute on the record every new
# subclass will instantly be marked as dirty and the type column will be included
- # in the list of changed attributes on the record. This is different from non
+ # in the list of changed attributes on the record. This is different from non
# STI classes:
#
# Company.new.changed? # => false
- # Firm.new.changed? # => true
- # Firm.new.changes # => {"type"=>["","Firm"]}
+ # Firm.new.changed? # => true
+ # Firm.new.changes # => {"type"=>["","Firm"]}
#
# If you don't have a type column defined in your table, single-table inheritance won't
# be triggered. In that case, it'll work just like normal subclasses with no special magic
diff --git a/activerecord/lib/active_record/migration.rb b/activerecord/lib/active_record/migration.rb
index 12eaf36156..e94b6ae9eb 100644
--- a/activerecord/lib/active_record/migration.rb
+++ b/activerecord/lib/active_record/migration.rb
@@ -366,22 +366,27 @@ module ActiveRecord
# This class is used to verify that all migrations have been run before
# loading a web page if config.active_record.migration_error is set to :page_load
class CheckPending
- def initialize(app, connection = Base.connection)
+ def initialize(app)
@app = app
- @connection = connection
@last_check = 0
end
def call(env)
- if @connection.supports_migrations?
+ if connection.supports_migrations?
mtime = ActiveRecord::Migrator.last_migration.mtime.to_i
if @last_check < mtime
- ActiveRecord::Migration.check_pending!(@connection)
+ ActiveRecord::Migration.check_pending!(connection)
@last_check = mtime
end
end
@app.call(env)
end
+
+ private
+
+ def connection
+ ActiveRecord::Base.connection
+ end
end
class << self
diff --git a/activerecord/lib/active_record/persistence.rb b/activerecord/lib/active_record/persistence.rb
index ee634d7bb3..96e44c2f59 100644
--- a/activerecord/lib/active_record/persistence.rb
+++ b/activerecord/lib/active_record/persistence.rb
@@ -396,6 +396,7 @@ module ActiveRecord
end
@attributes = fresh_object.instance_variable_get('@attributes')
+ @new_record = false
self
end
diff --git a/activerecord/lib/active_record/relation/calculations.rb b/activerecord/lib/active_record/relation/calculations.rb
index b4ae204813..90e99957f6 100644
--- a/activerecord/lib/active_record/relation/calculations.rb
+++ b/activerecord/lib/active_record/relation/calculations.rb
@@ -34,7 +34,7 @@ module ActiveRecord
# # => counts the number of different age values
#
# Note: not all valid +select+ expressions are valid +count+ expressions. The specifics differ
- # between databases. In invalid cases, an error from the databsae is thrown.
+ # between databases. In invalid cases, an error from the database is thrown.
def count(column_name = nil, options = {})
# TODO: Remove options argument as soon we remove support to
# activerecord-deprecated_finders.
diff --git a/activerecord/lib/active_record/tasks/database_tasks.rb b/activerecord/lib/active_record/tasks/database_tasks.rb
index 4727469420..9bc23b5ec7 100644
--- a/activerecord/lib/active_record/tasks/database_tasks.rb
+++ b/activerecord/lib/active_record/tasks/database_tasks.rb
@@ -176,12 +176,10 @@ module ActiveRecord
when :ruby
file ||= File.join(db_dir, "schema.rb")
check_schema_file(file)
- purge(current_config)
load(file)
when :sql
file ||= File.join(db_dir, "structure.sql")
check_schema_file(file)
- purge(current_config)
structure_load(current_config, file)
else
raise ArgumentError, "unknown format #{format.inspect}"
diff --git a/activerecord/lib/active_record/tasks/sqlite_database_tasks.rb b/activerecord/lib/active_record/tasks/sqlite_database_tasks.rb
index 9ab64d0325..5688931db2 100644
--- a/activerecord/lib/active_record/tasks/sqlite_database_tasks.rb
+++ b/activerecord/lib/active_record/tasks/sqlite_database_tasks.rb
@@ -21,11 +21,7 @@ module ActiveRecord
FileUtils.rm(file) if File.exist?(file)
end
-
- def purge
- drop
- create
- end
+ alias :purge :drop
def charset
connection.encoding
diff --git a/activerecord/lib/active_record/type/string.rb b/activerecord/lib/active_record/type/string.rb
index 14b03dcb2d..8cc533bc41 100644
--- a/activerecord/lib/active_record/type/string.rb
+++ b/activerecord/lib/active_record/type/string.rb
@@ -16,10 +16,10 @@ module ActiveRecord
end
def type_cast_for_database(value)
- if value.is_a?(::String)
- ::String.new(value)
- else
- super
+ case value
+ when ::Numeric then value.to_s
+ when ::String then ::String.new(value)
+ else super
end
end
diff --git a/activerecord/test/cases/adapters/postgresql/hstore_test.rb b/activerecord/test/cases/adapters/postgresql/hstore_test.rb
index 8f78dbecf5..2631b6a939 100644
--- a/activerecord/test/cases/adapters/postgresql/hstore_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/hstore_test.rb
@@ -112,13 +112,7 @@ class PostgresqlHstoreTest < ActiveRecord::TestCase
end
def test_type_cast_hstore
- assert @column
-
- data = "\"1\"=>\"2\""
- hash = @column.class.string_to_hstore data
- assert_equal({'1' => '2'}, hash)
- assert_equal({'1' => '2'}, @column.type_cast_from_database(data))
-
+ assert_equal({'1' => '2'}, @column.type_cast_from_database("\"1\"=>\"2\""))
assert_equal({}, @column.type_cast_from_database(""))
assert_equal({'key'=>nil}, @column.type_cast_from_database('key => NULL'))
assert_equal({'c'=>'}','"a"'=>'b "a b'}, @column.type_cast_from_database(%q(c=>"}", "\"a\""=>"b \"a b")))
@@ -173,19 +167,19 @@ class PostgresqlHstoreTest < ActiveRecord::TestCase
end
def test_gen1
- assert_equal(%q(" "=>""), @column.class.hstore_to_string({' '=>''}))
+ assert_equal(%q(" "=>""), @column.cast_type.type_cast_for_database({' '=>''}))
end
def test_gen2
- assert_equal(%q(","=>""), @column.class.hstore_to_string({','=>''}))
+ assert_equal(%q(","=>""), @column.cast_type.type_cast_for_database({','=>''}))
end
def test_gen3
- assert_equal(%q("="=>""), @column.class.hstore_to_string({'='=>''}))
+ assert_equal(%q("="=>""), @column.cast_type.type_cast_for_database({'='=>''}))
end
def test_gen4
- assert_equal(%q(">"=>""), @column.class.hstore_to_string({'>'=>''}))
+ assert_equal(%q(">"=>""), @column.cast_type.type_cast_for_database({'>'=>''}))
end
def test_parse1
diff --git a/activerecord/test/cases/adapters/postgresql/infinity_test.rb b/activerecord/test/cases/adapters/postgresql/infinity_test.rb
new file mode 100644
index 0000000000..22e8873333
--- /dev/null
+++ b/activerecord/test/cases/adapters/postgresql/infinity_test.rb
@@ -0,0 +1,44 @@
+require "cases/helper"
+
+class PostgresqlInfinityTest < ActiveRecord::TestCase
+ class PostgresqlInfinity < ActiveRecord::Base
+ end
+
+ setup do
+ @connection = ActiveRecord::Base.connection
+ @connection.create_table(:postgresql_infinities) do |t|
+ t.float :float
+ t.datetime :datetime
+ end
+ end
+
+ teardown do
+ @connection.execute("DROP TABLE IF EXISTS postgresql_infinities")
+ end
+
+ test "type casting infinity on a float column" do
+ record = PostgresqlInfinity.create!(float: Float::INFINITY)
+ record.reload
+ assert_equal Float::INFINITY, record.float
+ end
+
+ test "update_all with infinity on a float column" do
+ record = PostgresqlInfinity.create!
+ PostgresqlInfinity.update_all(float: Float::INFINITY)
+ record.reload
+ assert_equal Float::INFINITY, record.float
+ end
+
+ test "type casting infinity on a datetime column" do
+ record = PostgresqlInfinity.create!(datetime: Float::INFINITY)
+ record.reload
+ assert_equal Float::INFINITY, record.datetime
+ end
+
+ test "update_all with infinity on a datetime column" do
+ record = PostgresqlInfinity.create!
+ PostgresqlInfinity.update_all(datetime: Float::INFINITY)
+ record.reload
+ assert_equal Float::INFINITY, record.datetime
+ end
+end
diff --git a/activerecord/test/cases/adapters/postgresql/money_test.rb b/activerecord/test/cases/adapters/postgresql/money_test.rb
index cf2a4ab6ea..fa5e3cc281 100644
--- a/activerecord/test/cases/adapters/postgresql/money_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/money_test.rb
@@ -70,4 +70,28 @@ class PostgresqlMoneyTest < ActiveRecord::TestCase
money.reload
assert_equal new_value, money.wealth
end
+
+ def test_update_all_with_money_string
+ money = PostgresqlMoney.create!
+ PostgresqlMoney.update_all(wealth: "987.65")
+ money.reload
+
+ assert_equal 987.65, money.wealth
+ end
+
+ def test_update_all_with_money_big_decimal
+ money = PostgresqlMoney.create!
+ PostgresqlMoney.update_all(wealth: '123.45'.to_d)
+ money.reload
+
+ assert_equal 123.45, money.wealth
+ end
+
+ def test_update_all_with_money_numeric
+ money = PostgresqlMoney.create!
+ PostgresqlMoney.update_all(wealth: 123.45)
+ money.reload
+
+ assert_equal 123.45, money.wealth
+ end
end
diff --git a/activerecord/test/cases/adapters/postgresql/quoting_test.rb b/activerecord/test/cases/adapters/postgresql/quoting_test.rb
index 218c59247e..6f00c0d333 100644
--- a/activerecord/test/cases/adapters/postgresql/quoting_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/quoting_test.rb
@@ -57,6 +57,17 @@ module ActiveRecord
assert_equal "'1970-01-01 00:00:00.000000'", @conn.quote(Time.at(0))
assert_equal "'1970-01-01 00:00:00.000000'", @conn.quote(Time.at(0).to_datetime)
end
+
+ def test_quote_range
+ range = "1,2]'; SELECT * FROM users; --".."a"
+ c = PostgreSQLColumn.new(nil, nil, OID::Range.new(Type::Integer.new, :int8range))
+ assert_equal "'[1,2]''; SELECT * FROM users; --,a]'::int8range", @conn.quote(range, c)
+ end
+
+ def test_quote_bit_string
+ c = PostgreSQLColumn.new(nil, 1, OID::Bit.new)
+ assert_equal nil, @conn.quote("'); SELECT * FORM users; /*\n01\n*/--", c)
+ end
end
end
end
diff --git a/activerecord/test/cases/adapters/postgresql/range_test.rb b/activerecord/test/cases/adapters/postgresql/range_test.rb
index 0f6e39322c..02d0a9b483 100644
--- a/activerecord/test/cases/adapters/postgresql/range_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/range_test.rb
@@ -262,6 +262,23 @@ _SQL
assert_raises(ArgumentError) { PostgresqlRange.create!(float_range: "(0.5, 0.7]") }
end
+ def test_update_all_with_ranges
+ PostgresqlRange.create!
+
+ PostgresqlRange.update_all(int8_range: 1..100)
+
+ assert_equal 1...101, PostgresqlRange.first.int8_range
+ end
+
+ def test_ranges_correctly_escape_input
+ e = assert_raises(ActiveRecord::StatementInvalid) do
+ range = "1,2]'; SELECT * FROM users; --".."a"
+ PostgresqlRange.update_all(int8_range: range)
+ end
+
+ assert e.message.starts_with?("PG::InvalidTextRepresentation")
+ end
+
private
def assert_equal_round_trip(range, attribute, value)
round_trip(range, attribute, value)
diff --git a/activerecord/test/cases/counter_cache_test.rb b/activerecord/test/cases/counter_cache_test.rb
index ab2a749ba8..07a182070b 100644
--- a/activerecord/test/cases/counter_cache_test.rb
+++ b/activerecord/test/cases/counter_cache_test.rb
@@ -19,6 +19,7 @@ class CounterCacheTest < ActiveRecord::TestCase
class ::SpecialTopic < ::Topic
has_many :special_replies, :foreign_key => 'parent_id'
+ has_many :lightweight_special_replies, -> { select('topics.id, topics.title') }, :foreign_key => 'parent_id', :class_name => 'SpecialReply'
end
class ::SpecialReply < ::Reply
@@ -170,4 +171,13 @@ class CounterCacheTest < ActiveRecord::TestCase
end
assert_equal "'Topic' has no association called 'undefined_count'", e.message
end
+
+ test "reset counter works with select declared on association" do
+ special = SpecialTopic.create!(:title => 'Special')
+ SpecialTopic.increment_counter(:replies_count, special.id)
+
+ assert_difference 'special.reload.replies_count', -1 do
+ SpecialTopic.reset_counters(special.id, :lightweight_special_replies)
+ end
+ end
end
diff --git a/activerecord/test/cases/dup_test.rb b/activerecord/test/cases/dup_test.rb
index 409d9a82e2..638cffe0e6 100644
--- a/activerecord/test/cases/dup_test.rb
+++ b/activerecord/test/cases/dup_test.rb
@@ -141,5 +141,17 @@ module ActiveRecord
ensure
Topic.default_scopes = prev_default_scopes
end
+
+ def test_dup_without_primary_key
+ klass = Class.new(ActiveRecord::Base) do
+ self.table_name = 'parrots_pirates'
+ end
+
+ record = klass.create!
+
+ assert_nothing_raised do
+ record.dup
+ end
+ end
end
end
diff --git a/activerecord/test/cases/migration/pending_migrations_test.rb b/activerecord/test/cases/migration/pending_migrations_test.rb
index eff000e1a4..517ee695ce 100644
--- a/activerecord/test/cases/migration/pending_migrations_test.rb
+++ b/activerecord/test/cases/migration/pending_migrations_test.rb
@@ -8,14 +8,17 @@ module ActiveRecord
super
@connection = MiniTest::Mock.new
@app = MiniTest::Mock.new
- @pending = CheckPending.new(@app, @connection)
+ conn = @connection
+ @pending = Class.new(CheckPending) {
+ define_method(:connection) { conn }
+ }.new(@app)
@pending.instance_variable_set :@last_check, -1 # Force checking
end
def teardown
- super
assert @connection.verify
assert @app.verify
+ super
end
def test_errors_if_pending
diff --git a/activerecord/test/cases/persistence_test.rb b/activerecord/test/cases/persistence_test.rb
index 1192ecd6b4..9b762fc0d5 100644
--- a/activerecord/test/cases/persistence_test.rb
+++ b/activerecord/test/cases/persistence_test.rb
@@ -865,4 +865,16 @@ class PersistenceTest < ActiveRecord::TestCase
assert_equal 1, post[:wibble]
assert_nil post.reload[:wibble]
end
+
+ def test_find_via_reload
+ post = Post.new
+
+ assert post.new_record?
+
+ post.id = 1
+ post.reload
+
+ assert_equal "Welcome to the weblog", post.title
+ assert_not post.new_record?
+ end
end
diff --git a/activerecord/test/cases/reflection_test.rb b/activerecord/test/cases/reflection_test.rb
index acbd065649..b41a7ee787 100644
--- a/activerecord/test/cases/reflection_test.rb
+++ b/activerecord/test/cases/reflection_test.rb
@@ -412,6 +412,38 @@ class ReflectionTest < ActiveRecord::TestCase
assert_equal 'product_categories', reflection.join_table
end
+ def test_includes_accepts_symbols
+ hotel = Hotel.create!
+ department = hotel.departments.create!
+ department.chefs.create!
+
+ assert_nothing_raised do
+ assert_equal department.chefs, Hotel.includes([departments: :chefs]).first.chefs
+ end
+ end
+
+ def test_includes_accepts_strings
+ hotel = Hotel.create!
+ department = hotel.departments.create!
+ department.chefs.create!
+
+ assert_nothing_raised do
+ assert_equal department.chefs, Hotel.includes(['departments' => 'chefs']).first.chefs
+ end
+ end
+
+ def test_reflect_on_association_accepts_symbols
+ assert_nothing_raised do
+ assert_equal Hotel.reflect_on_association(:departments).name, :departments
+ end
+ end
+
+ def test_reflect_on_association_accepts_strings
+ assert_nothing_raised do
+ assert_equal Hotel.reflect_on_association("departments").name, :departments
+ end
+ end
+
private
def assert_reflection(klass, association, options)
assert reflection = klass.reflect_on_association(association)