aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord
diff options
context:
space:
mode:
Diffstat (limited to 'activerecord')
-rw-r--r--activerecord/lib/active_record/attribute_methods/read.rb100
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/quoting.rb3
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb2
-rw-r--r--activerecord/lib/active_record/counter_cache.rb6
-rw-r--r--activerecord/lib/active_record/relation.rb4
-rw-r--r--activerecord/lib/active_record/test_case.rb35
-rw-r--r--activerecord/test/cases/adapters/sqlite3/quoting_test.rb4
-rw-r--r--activerecord/test/cases/base_test.rb10
-rw-r--r--activerecord/test/cases/helper.rb2
-rw-r--r--activerecord/test/cases/migration/index_test.rb8
-rw-r--r--activerecord/test/cases/test_case.rb63
11 files changed, 139 insertions, 98 deletions
diff --git a/activerecord/lib/active_record/attribute_methods/read.rb b/activerecord/lib/active_record/attribute_methods/read.rb
index 964c4123ef..3549cbb090 100644
--- a/activerecord/lib/active_record/attribute_methods/read.rb
+++ b/activerecord/lib/active_record/attribute_methods/read.rb
@@ -58,66 +58,68 @@ module ActiveRecord
end
protected
- # We want to generate the methods via module_eval rather than define_method,
- # because define_method is slower on dispatch and uses more memory (because it
- # creates a closure).
- #
- # But sometimes the database might return columns with characters that are not
- # allowed in normal method names (like 'my_column(omg)'. So to work around this
- # we first define with the __temp__ identifier, and then use alias method to
- # rename it to what we want.
- def define_method_attribute(attr_name)
- cast_code = attribute_cast_code(attr_name)
-
- generated_attribute_methods.module_eval <<-STR, __FILE__, __LINE__ + 1
- def __temp__
- #{internal_attribute_access_code(attr_name, cast_code)}
- end
- alias_method '#{attr_name}', :__temp__
- undef_method :__temp__
- STR
-
- generated_external_attribute_methods.module_eval <<-STR, __FILE__, __LINE__ + 1
- def __temp__(v, attributes, attributes_cache, attr_name)
- #{external_attribute_access_code(attr_name, cast_code)}
- end
- alias_method '#{attr_name}', :__temp__
- undef_method :__temp__
- STR
- end
+ # We want to generate the methods via module_eval rather than define_method,
+ # because define_method is slower on dispatch and uses more memory (because it
+ # creates a closure).
+ #
+ # But sometimes the database might return columns with characters that are not
+ # allowed in normal method names (like 'my_column(omg)'. So to work around this
+ # we first define with the __temp__ identifier, and then use alias method to
+ # rename it to what we want.
+ def define_method_attribute(attr_name)
+ cast_code = attribute_cast_code(attr_name)
+
+ generated_attribute_methods.module_eval <<-STR, __FILE__, __LINE__ + 1
+ def __temp__
+ #{internal_attribute_access_code(attr_name, cast_code)}
+ end
+ alias_method '#{attr_name}', :__temp__
+ undef_method :__temp__
+ STR
- private
- def cacheable_column?(column)
- attribute_types_cached_by_default.include?(column.type)
- end
+ generated_external_attribute_methods.module_eval <<-STR, __FILE__, __LINE__ + 1
+ def __temp__(v, attributes, attributes_cache, attr_name)
+ #{external_attribute_access_code(attr_name, cast_code)}
+ end
+ alias_method '#{attr_name}', :__temp__
+ undef_method :__temp__
+ STR
+ end
- def internal_attribute_access_code(attr_name, cast_code)
- access_code = "(v=@attributes[attr_name]) && #{cast_code}"
+ private
+ def cacheable_column?(column)
+ attribute_types_cached_by_default.include?(column.type)
+ end
- unless attr_name == primary_key
- access_code.insert(0, "missing_attribute(attr_name, caller) unless @attributes.has_key?(attr_name); ")
- end
+ def internal_attribute_access_code(attr_name, cast_code)
+ if attr_name == primary_key
+ access_code = "v = @attributes[attr_name];"
+ else
+ access_code = "v = @attributes.fetch(attr_name) { missing_attribute(attr_name, caller) };"
+ end
- if cache_attribute?(attr_name)
- access_code = "@attributes_cache[attr_name] ||= (#{access_code})"
- end
+ access_code << "v && #{cast_code};"
- "attr_name = '#{attr_name}'; #{access_code}"
+ if cache_attribute?(attr_name)
+ access_code = "@attributes_cache[attr_name] ||= (#{access_code})"
end
- def external_attribute_access_code(attr_name, cast_code)
- access_code = "v && #{cast_code}"
+ "attr_name = '#{attr_name}'; #{access_code}"
+ end
- if cache_attribute?(attr_name)
- access_code = "attributes_cache[attr_name] ||= (#{access_code})"
- end
+ def external_attribute_access_code(attr_name, cast_code)
+ access_code = "v && #{cast_code}"
- access_code
+ if cache_attribute?(attr_name)
+ access_code = "attributes_cache[attr_name] ||= (#{access_code})"
end
- def attribute_cast_code(attr_name)
- columns_hash[attr_name].type_cast_code('v')
- end
+ access_code
+ end
+
+ def attribute_cast_code(attr_name)
+ columns_hash[attr_name].type_cast_code('v')
+ end
end
# Returns the value of the attribute identified by <tt>attr_name</tt> after it has been typecast (for example,
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb b/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb
index f93c7cd74a..44ac37c498 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb
@@ -71,7 +71,8 @@ module ActiveRecord
when Date, Time then quoted_date(value)
when Symbol then value.to_s
else
- YAML.dump(value)
+ to_type = column ? " to #{column.type}" : ""
+ raise TypeError, "can't cast #{value.class}#{to_type}"
end
end
diff --git a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb
index 560773ca86..201c05d8f5 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb
@@ -541,7 +541,7 @@ module ActiveRecord
if options.is_a?(Hash) && length = options[:length]
case length
when Hash
- column_names.each {|name| option_strings[name] += "(#{length[name]})" if length.has_key?(name)}
+ column_names.each {|name| option_strings[name] += "(#{length[name]})" if length.has_key?(name) && length[name].present?}
when Fixnum
column_names.each {|name| option_strings[name] += "(#{length})"}
end
diff --git a/activerecord/lib/active_record/counter_cache.rb b/activerecord/lib/active_record/counter_cache.rb
index c9c46b8d4f..224f5276eb 100644
--- a/activerecord/lib/active_record/counter_cache.rb
+++ b/activerecord/lib/active_record/counter_cache.rb
@@ -19,12 +19,6 @@ module ActiveRecord
counters.each do |association|
has_many_association = reflect_on_association(association.to_sym)
- expected_name = if has_many_association.options[:as]
- has_many_association.options[:as].to_s.classify
- else
- self.name
- end
-
foreign_key = has_many_association.foreign_key.to_s
child_class = has_many_association.klass
belongs_to = child_class.reflect_on_all_associations(:belongs_to)
diff --git a/activerecord/lib/active_record/relation.rb b/activerecord/lib/active_record/relation.rb
index 01019db2cc..ac70aeba67 100644
--- a/activerecord/lib/active_record/relation.rb
+++ b/activerecord/lib/active_record/relation.rb
@@ -496,6 +496,10 @@ module ActiveRecord
to_a.inspect
end
+ def pretty_print(q)
+ q.pp(self.to_a)
+ end
+
def with_default_scope #:nodoc:
if default_scoped? && default_scope = klass.send(:build_default_scope)
default_scope = default_scope.merge(self)
diff --git a/activerecord/lib/active_record/test_case.rb b/activerecord/lib/active_record/test_case.rb
index 64ecef2077..86687afdda 100644
--- a/activerecord/lib/active_record/test_case.rb
+++ b/activerecord/lib/active_record/test_case.rb
@@ -1,3 +1,7 @@
+require 'active_support/deprecation'
+require 'active_support/test_case'
+
+ActiveSupport::Deprecation.warn('ActiveRecord::TestCase is deprecated, please use ActiveSupport::TestCase')
module ActiveRecord
# = Active Record Test Case
#
@@ -26,36 +30,5 @@ module ActiveRecord
assert_equal expected.to_s, actual.to_s, message
end
end
-
- def assert_sql(*patterns_to_match)
- ActiveRecord::SQLCounter.log = []
- yield
- ActiveRecord::SQLCounter.log
- ensure
- failed_patterns = []
- patterns_to_match.each do |pattern|
- failed_patterns << pattern unless ActiveRecord::SQLCounter.log.any?{ |sql| pattern === sql }
- end
- assert failed_patterns.empty?, "Query pattern(s) #{failed_patterns.map{ |p| p.inspect }.join(', ')} not found.#{ActiveRecord::SQLCounter.log.size == 0 ? '' : "\nQueries:\n#{ActiveRecord::SQLCounter.log.join("\n")}"}"
- end
-
- def assert_queries(num = 1)
- ActiveRecord::SQLCounter.log = []
- yield
- ensure
- assert_equal num, ActiveRecord::SQLCounter.log.size, "#{ActiveRecord::SQLCounter.log.size} instead of #{num} queries were executed.#{ActiveRecord::SQLCounter.log.size == 0 ? '' : "\nQueries:\n#{ActiveRecord::SQLCounter.log.join("\n")}"}"
- end
-
- def assert_no_queries(&block)
- prev_ignored_sql = ActiveRecord::SQLCounter.ignored_sql
- ActiveRecord::SQLCounter.ignored_sql = []
- assert_queries(0, &block)
- ensure
- ActiveRecord::SQLCounter.ignored_sql = prev_ignored_sql
- end
-
- def sqlite3? connection
- connection.class.name.split('::').last == "SQLite3Adapter"
- end
end
end
diff --git a/activerecord/test/cases/adapters/sqlite3/quoting_test.rb b/activerecord/test/cases/adapters/sqlite3/quoting_test.rb
index e0152e7ccf..46da1b0a2b 100644
--- a/activerecord/test/cases/adapters/sqlite3/quoting_test.rb
+++ b/activerecord/test/cases/adapters/sqlite3/quoting_test.rb
@@ -70,9 +70,9 @@ module ActiveRecord
assert_equal bd.to_f, @conn.type_cast(bd, nil)
end
- def test_type_cast_unknown
+ def test_type_cast_unknown_should_raise_error
obj = Class.new.new
- assert_equal YAML.dump(obj), @conn.type_cast(obj, nil)
+ assert_raise(TypeError) { @conn.type_cast(obj, nil) }
end
def test_quoted_id
diff --git a/activerecord/test/cases/base_test.rb b/activerecord/test/cases/base_test.rb
index 87a3a0deb9..0ea1b824e1 100644
--- a/activerecord/test/cases/base_test.rb
+++ b/activerecord/test/cases/base_test.rb
@@ -992,10 +992,9 @@ class BasicsTest < ActiveRecord::TestCase
assert_equal "b", duped_topic.title
# test if the attribute values have been duped
- topic.title = {"a" => "b"}
duped_topic = topic.dup
- duped_topic.title["a"] = "c"
- assert_equal "b", topic.title["a"]
+ duped_topic.title.replace "c"
+ assert_equal "a", topic.title
# test if attributes set as part of after_initialize are duped correctly
assert_equal topic.author_email_address, duped_topic.author_email_address
@@ -1006,8 +1005,7 @@ class BasicsTest < ActiveRecord::TestCase
assert_not_equal duped_topic.id, topic.id
duped_topic.reload
- # FIXME: I think this is poor behavior, and will fix it with #5686
- assert_equal({'a' => 'c'}.to_yaml, duped_topic.title)
+ assert_equal("c", duped_topic.title)
end
def test_dup_with_aggregate_of_same_name_as_attribute
@@ -1893,7 +1891,7 @@ class BasicsTest < ActiveRecord::TestCase
assert_equal [], NonExistentTable.attribute_names
end
- def test_attribtue_names_on_abstract_class
+ def test_attribute_names_on_abstract_class
assert_equal [], AbstractCompany.attribute_names
end
diff --git a/activerecord/test/cases/helper.rb b/activerecord/test/cases/helper.rb
index d16cccdaea..b4598ab32a 100644
--- a/activerecord/test/cases/helper.rb
+++ b/activerecord/test/cases/helper.rb
@@ -6,8 +6,8 @@ require 'minitest/autorun'
require 'stringio'
require 'mocha'
+require 'cases/test_case'
require 'active_record'
-require 'active_record/test_case'
require 'active_support/dependencies'
require 'active_support/logger'
diff --git a/activerecord/test/cases/migration/index_test.rb b/activerecord/test/cases/migration/index_test.rb
index 26d7aeb148..89cf0f5e93 100644
--- a/activerecord/test/cases/migration/index_test.rb
+++ b/activerecord/test/cases/migration/index_test.rb
@@ -55,7 +55,7 @@ module ActiveRecord
assert_raise(ArgumentError) { connection.remove_index(table_name, "no_such_index") }
end
- def test_add_index_length_limit
+ def test_add_index_name_length_limit
good_index_name = 'x' * connection.index_name_length
too_long_index_name = good_index_name + 'x'
@@ -103,6 +103,12 @@ module ActiveRecord
assert connection.index_exists?(:testings, :foo, :name => "custom_index_name")
end
+ def test_add_index_attribute_length_limit
+ connection.add_index :testings, [:foo, :bar], :length => {:foo => 10, :bar => nil}
+
+ assert connection.index_exists?(:testings, [:foo, :bar])
+ end
+
def test_add_index
connection.add_index("testings", "last_name")
connection.remove_index("testings", "last_name")
diff --git a/activerecord/test/cases/test_case.rb b/activerecord/test/cases/test_case.rb
new file mode 100644
index 0000000000..f0fefe6c48
--- /dev/null
+++ b/activerecord/test/cases/test_case.rb
@@ -0,0 +1,63 @@
+require 'active_support/test_case'
+
+module ActiveRecord
+ # = Active Record Test Case
+ #
+ # Defines some test assertions to test against SQL queries.
+ class TestCase < ActiveSupport::TestCase #:nodoc:
+ setup :cleanup_identity_map
+
+ def setup
+ cleanup_identity_map
+ end
+
+ def teardown
+ ActiveRecord::SQLCounter.log.clear
+ end
+
+ def cleanup_identity_map
+ ActiveRecord::IdentityMap.clear
+ end
+
+ def assert_date_from_db(expected, actual, message = nil)
+ # SybaseAdapter doesn't have a separate column type just for dates,
+ # so the time is in the string and incorrectly formatted
+ if current_adapter?(:SybaseAdapter)
+ assert_equal expected.to_s, actual.to_date.to_s, message
+ else
+ assert_equal expected.to_s, actual.to_s, message
+ end
+ end
+
+ def assert_sql(*patterns_to_match)
+ ActiveRecord::SQLCounter.log = []
+ yield
+ ActiveRecord::SQLCounter.log
+ ensure
+ failed_patterns = []
+ patterns_to_match.each do |pattern|
+ failed_patterns << pattern unless ActiveRecord::SQLCounter.log.any?{ |sql| pattern === sql }
+ end
+ assert failed_patterns.empty?, "Query pattern(s) #{failed_patterns.map{ |p| p.inspect }.join(', ')} not found.#{ActiveRecord::SQLCounter.log.size == 0 ? '' : "\nQueries:\n#{ActiveRecord::SQLCounter.log.join("\n")}"}"
+ end
+
+ def assert_queries(num = 1)
+ ActiveRecord::SQLCounter.log = []
+ yield
+ ensure
+ assert_equal num, ActiveRecord::SQLCounter.log.size, "#{ActiveRecord::SQLCounter.log.size} instead of #{num} queries were executed.#{ActiveRecord::SQLCounter.log.size == 0 ? '' : "\nQueries:\n#{ActiveRecord::SQLCounter.log.join("\n")}"}"
+ end
+
+ def assert_no_queries(&block)
+ prev_ignored_sql = ActiveRecord::SQLCounter.ignored_sql
+ ActiveRecord::SQLCounter.ignored_sql = []
+ assert_queries(0, &block)
+ ensure
+ ActiveRecord::SQLCounter.ignored_sql = prev_ignored_sql
+ end
+
+ def sqlite3? connection
+ connection.class.name.split('::').last == "SQLite3Adapter"
+ end
+ end
+end