aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord
diff options
context:
space:
mode:
authorPratik Naik <pratiknaik@gmail.com>2008-09-27 14:04:46 +0100
committerPratik Naik <pratiknaik@gmail.com>2008-09-27 14:04:46 +0100
commitfda846cf5ddf523b00a39c26591489794b5de568 (patch)
tree00d4860d53e5c861fd9b3f483f04ff0d2db19307 /activerecord
parentdf046298715b1927a832973c4c29955696fee02c (diff)
parentea609b265ffc30cac00bf09a262027f96964ed6f (diff)
downloadrails-fda846cf5ddf523b00a39c26591489794b5de568.tar.gz
rails-fda846cf5ddf523b00a39c26591489794b5de568.tar.bz2
rails-fda846cf5ddf523b00a39c26591489794b5de568.zip
Merge commit 'mainstream/master'
Conflicts: activerecord/lib/active_record/base.rb railties/Rakefile railties/doc/guides/activerecord/association_basics.txt railties/doc/guides/debugging/debugging_rails_applications.txt railties/doc/guides/getting_started_with_rails/getting_started_with_rails.txt railties/doc/guides/index.txt railties/doc/guides/migrations/foreign_keys.txt railties/doc/guides/migrations/migrations.txt railties/doc/guides/migrations/writing_a_migration.txt railties/doc/guides/routing/routing_outside_in.txt
Diffstat (limited to 'activerecord')
-rw-r--r--activerecord/CHANGELOG8
-rw-r--r--activerecord/lib/active_record.rb4
-rwxr-xr-xactiverecord/lib/active_record/associations.rb55
-rw-r--r--activerecord/lib/active_record/associations/association_collection.rb32
-rw-r--r--activerecord/lib/active_record/associations/has_many_association.rb5
-rw-r--r--activerecord/lib/active_record/associations/has_many_through_association.rb4
-rw-r--r--activerecord/lib/active_record/attribute_methods.rb10
-rwxr-xr-xactiverecord/lib/active_record/base.rb46
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb4
-rw-r--r--activerecord/lib/active_record/connection_adapters/mysql_adapter.rb7
-rw-r--r--activerecord/lib/active_record/i18n_interpolation_deprecation.rb26
-rw-r--r--activerecord/lib/active_record/schema_dumper.rb2
-rw-r--r--activerecord/lib/active_record/validations.rb4
-rw-r--r--activerecord/lib/active_record/version.rb2
-rw-r--r--activerecord/test/cases/associations/extension_test.rb15
-rw-r--r--activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb11
-rw-r--r--activerecord/test/cases/associations/has_many_associations_test.rb24
-rw-r--r--activerecord/test/cases/associations/has_many_through_associations_test.rb9
-rw-r--r--activerecord/test/cases/associations_test.rb8
-rw-r--r--activerecord/test/cases/attribute_methods_test.rb60
-rwxr-xr-x[-rw-r--r--]activerecord/test/cases/base_test.rb74
-rw-r--r--activerecord/test/cases/defaults_test.rb31
-rw-r--r--activerecord/test/cases/finder_test.rb15
-rw-r--r--activerecord/test/cases/helper.rb14
-rw-r--r--activerecord/test/cases/method_scoping_test.rb30
-rw-r--r--activerecord/test/cases/migration_test.rb6
-rw-r--r--activerecord/test/cases/named_scope_test.rb6
-rw-r--r--activerecord/test/cases/sanitize_test.rb8
-rw-r--r--activerecord/test/cases/validations_i18n_test.rb6
29 files changed, 463 insertions, 63 deletions
diff --git a/activerecord/CHANGELOG b/activerecord/CHANGELOG
index 5bcc7ad3a9..6479cc5a9b 100644
--- a/activerecord/CHANGELOG
+++ b/activerecord/CHANGELOG
@@ -1,5 +1,13 @@
*Edge*
+* Add Model#delete instance method, similar to Model.delete class method. #1086 [Hongli Lai]
+
+* MySQL: cope with quirky default values for not-null text columns. #1043 [Frederick Cheung]
+
+* Multiparameter attributes skip time zone conversion for time-only columns [#1030 state:resolved] [Geoff Buesing]
+
+* Base.skip_time_zone_conversion_for_attributes uses class_inheritable_accessor, so that subclasses don't overwrite Base [#346 state:resolved] [miloops]
+
* Added find_last_by dynamic finder #762 [miloops]
* Internal API: configurable association options and build_association method for reflections so plugins may extend and override. #985 [Hongli Lai]
diff --git a/activerecord/lib/active_record.rb b/activerecord/lib/active_record.rb
index a6bbd6fc82..219cd30f94 100644
--- a/activerecord/lib/active_record.rb
+++ b/activerecord/lib/active_record.rb
@@ -77,5 +77,5 @@ require 'active_record/connection_adapters/abstract_adapter'
require 'active_record/schema_dumper'
-I18n.load_translations File.dirname(__FILE__) + '/active_record/locale/en-US.yml'
-
+require 'active_record/i18n_interpolation_deprecation'
+I18n.load_path << File.dirname(__FILE__) + '/active_record/locale/en-US.yml'
diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb
index 33457822ff..4d36216c34 100755
--- a/activerecord/lib/active_record/associations.rb
+++ b/activerecord/lib/active_record/associations.rb
@@ -1026,7 +1026,7 @@ module ActiveRecord
# Create the callbacks to update counter cache
if options[:counter_cache]
cache_column = options[:counter_cache] == true ?
- "#{self.to_s.underscore.pluralize}_count" :
+ "#{self.to_s.demodulize.underscore.pluralize}_count" :
options[:counter_cache]
method_name = "belongs_to_counter_cache_after_create_for_#{reflection.name}".to_sym
@@ -1268,7 +1268,11 @@ module ActiveRecord
if association_proxy_class == BelongsToAssociation
define_method("#{reflection.primary_key_name}=") do |target_id|
- instance_variable_get(ivar).reset if instance_variable_defined?(ivar)
+ if instance_variable_defined?(ivar)
+ if association = instance_variable_get(ivar)
+ association.reset
+ end
+ end
write_attribute(reflection.primary_key_name, target_id)
end
end
@@ -1424,15 +1428,23 @@ module ActiveRecord
[]
end
+ # Creates before_destroy callback methods that nullify, delete or destroy
+ # has_many associated objects, according to the defined :dependent rule.
+ #
# See HasManyAssociation#delete_records. Dependent associations
# delete children, otherwise foreign key is set to NULL.
- def configure_dependency_for_has_many(reflection)
+ #
+ # The +extra_conditions+ parameter, which is not used within the main
+ # Active Record codebase, is meant to allow plugins to define extra
+ # finder conditions.
+ def configure_dependency_for_has_many(reflection, extra_conditions = nil)
if reflection.options.include?(:dependent)
# Add polymorphic type if the :as option is present
dependent_conditions = []
dependent_conditions << "#{reflection.primary_key_name} = \#{record.quoted_id}"
dependent_conditions << "#{reflection.options[:as]}_type = '#{base_class.name}'" if reflection.options[:as]
dependent_conditions << sanitize_sql(reflection.options[:conditions]) if reflection.options[:conditions]
+ dependent_conditions << extra_conditions if extra_conditions
dependent_conditions = dependent_conditions.collect {|where| "(#{where})" }.join(" AND ")
case reflection.options[:dependent]
@@ -1443,9 +1455,24 @@ module ActiveRecord
end
before_destroy method_name
when :delete_all
- module_eval "before_destroy { |record| #{reflection.class_name}.delete_all(%(#{dependent_conditions})) }"
+ module_eval %Q{
+ before_destroy do |record|
+ delete_all_has_many_dependencies(record,
+ "#{reflection.name}",
+ #{reflection.class_name},
+ "#{dependent_conditions}")
+ end
+ }
when :nullify
- module_eval "before_destroy { |record| #{reflection.class_name}.update_all(%(#{reflection.primary_key_name} = NULL), %(#{dependent_conditions})) }"
+ module_eval %Q{
+ before_destroy do |record|
+ nullify_has_many_dependencies(record,
+ "#{reflection.name}",
+ #{reflection.class_name},
+ "#{reflection.primary_key_name}",
+ "#{dependent_conditions}")
+ end
+ }
else
raise ArgumentError, "The :dependent option expects either :destroy, :delete_all, or :nullify (#{reflection.options[:dependent].inspect})"
end
@@ -1472,7 +1499,7 @@ module ActiveRecord
# with foreign keys pointing to this object, and we only want
# to delete the correct one, not all of them.
association = send(reflection.name)
- association.class.delete(association.id) unless association.nil?
+ association.delete unless association.nil?
end
before_destroy method_name
when :nullify
@@ -1502,7 +1529,7 @@ module ActiveRecord
method_name = "belongs_to_dependent_delete_for_#{reflection.name}".to_sym
define_method(method_name) do
association = send(reflection.name)
- association.class.delete(association.id) unless association.nil?
+ association.delete unless association.nil?
end
before_destroy method_name
else
@@ -1511,6 +1538,14 @@ module ActiveRecord
end
end
+ def delete_all_has_many_dependencies(record, reflection_name, association_class, dependent_conditions)
+ association_class.delete_all(dependent_conditions)
+ end
+
+ def nullify_has_many_dependencies(record, reflection_name, association_class, primary_key_name, dependent_conditions)
+ association_class.update_all("#{primary_key_name} = NULL", dependent_conditions)
+ end
+
mattr_accessor :valid_keys_for_has_many_association
@@valid_keys_for_has_many_association = [
:class_name, :table_name, :foreign_key, :primary_key,
@@ -1757,12 +1792,12 @@ module ActiveRecord
def create_extension_modules(association_id, block_extension, extensions)
if block_extension
- extension_module_name = "#{self.to_s}#{association_id.to_s.camelize}AssociationExtension"
+ extension_module_name = "#{self.to_s.demodulize}#{association_id.to_s.camelize}AssociationExtension"
silence_warnings do
- Object.const_set(extension_module_name, Module.new(&block_extension))
+ self.parent.const_set(extension_module_name, Module.new(&block_extension))
end
- Array(extensions).push(extension_module_name.constantize)
+ Array(extensions).push("#{self.parent}::#{extension_module_name}".constantize)
else
Array(extensions)
end
diff --git a/activerecord/lib/active_record/associations/association_collection.rb b/activerecord/lib/active_record/associations/association_collection.rb
index 8de528f638..463de9d819 100644
--- a/activerecord/lib/active_record/associations/association_collection.rb
+++ b/activerecord/lib/active_record/associations/association_collection.rb
@@ -63,7 +63,7 @@ module ActiveRecord
# Fetches the first one using SQL if possible.
def first(*args)
- if fetch_first_or_last_using_find? args
+ if fetch_first_or_last_using_find?(args)
find(:first, *args)
else
load_target unless loaded?
@@ -73,7 +73,7 @@ module ActiveRecord
# Fetches the last one using SQL if possible.
def last(*args)
- if fetch_first_or_last_using_find? args
+ if fetch_first_or_last_using_find?(args)
find(:last, *args)
else
load_target unless loaded?
@@ -108,7 +108,7 @@ module ActiveRecord
result = true
load_target if @owner.new_record?
- @owner.transaction do
+ transaction do
flatten_deeper(records).each do |record|
raise_on_type_mismatch(record)
add_record_to_target_with_callbacks(record) do |r|
@@ -123,6 +123,21 @@ module ActiveRecord
alias_method :push, :<<
alias_method :concat, :<<
+ # Starts a transaction in the association class's database connection.
+ #
+ # class Author < ActiveRecord::Base
+ # has_many :books
+ # end
+ #
+ # Author.find(:first).books.transaction do
+ # # same effect as calling Book.transaction
+ # end
+ def transaction(*args)
+ @reflection.klass.transaction(*args) do
+ yield
+ end
+ end
+
# Remove all records from this association
def delete_all
load_target
@@ -173,7 +188,7 @@ module ActiveRecord
records = flatten_deeper(records)
records.each { |record| raise_on_type_mismatch(record) }
- @owner.transaction do
+ transaction do
records.each { |record| callback(:before_remove, record) }
old_records = records.reject {|r| r.new_record? }
@@ -200,7 +215,7 @@ module ActiveRecord
end
def destroy_all
- @owner.transaction do
+ transaction do
each { |record| record.destroy }
end
@@ -238,6 +253,8 @@ module ActiveRecord
def size
if @owner.new_record? || (loaded? && !@reflection.options[:uniq])
@target.size
+ elsif !loaded? && @reflection.options[:group]
+ load_target.size
elsif !loaded? && !@reflection.options[:uniq] && @target.is_a?(Array)
unsaved_records = @target.select { |r| r.new_record? }
unsaved_records.size + count_records
@@ -290,7 +307,7 @@ module ActiveRecord
other = other_array.size < 100 ? other_array : other_array.to_set
current = @target.size < 100 ? @target : @target.to_set
- @owner.transaction do
+ transaction do
delete(@target.select { |v| !other.include?(v) })
concat(other_array.select { |v| !current.include?(v) })
end
@@ -418,7 +435,8 @@ module ActiveRecord
end
def fetch_first_or_last_using_find?(args)
- args.first.kind_of?(Hash) || !(loaded? || @owner.new_record? || @reflection.options[:finder_sql] || !@target.blank? || args.first.kind_of?(Integer))
+ args.first.kind_of?(Hash) || !(loaded? || @owner.new_record? || @reflection.options[:finder_sql] ||
+ @target.any? { |record| record.new_record? } || args.first.kind_of?(Integer))
end
end
end
diff --git a/activerecord/lib/active_record/associations/has_many_association.rb b/activerecord/lib/active_record/associations/has_many_association.rb
index dda22668c6..3b2f306637 100644
--- a/activerecord/lib/active_record/associations/has_many_association.rb
+++ b/activerecord/lib/active_record/associations/has_many_association.rb
@@ -17,7 +17,10 @@ module ActiveRecord
# Returns the number of records in this collection.
#
# If the association has a counter cache it gets that value. Otherwise
- # a count via SQL is performed, bounded to <tt>:limit</tt> if there's one.
+ # it will attempt to do a count via SQL, bounded to <tt>:limit</tt> if
+ # there's one. Some configuration options like :group make it impossible
+ # to do a SQL count, in those cases the array count will be used.
+ #
# That does not depend on whether the collection has already been loaded
# or not. The +size+ method is the one that takes the loaded flag into
# account and delegates to +count_records+ if needed.
diff --git a/activerecord/lib/active_record/associations/has_many_through_association.rb b/activerecord/lib/active_record/associations/has_many_through_association.rb
index ebd2bf768c..3171665e19 100644
--- a/activerecord/lib/active_record/associations/has_many_through_association.rb
+++ b/activerecord/lib/active_record/associations/has_many_through_association.rb
@@ -9,14 +9,14 @@ module ActiveRecord
alias_method :new, :build
def create!(attrs = nil)
- @reflection.klass.transaction do
+ transaction do
self << (object = attrs ? @reflection.klass.send(:with_scope, :create => attrs) { @reflection.create_association! } : @reflection.create_association!)
object
end
end
def create(attrs = nil)
- @reflection.klass.transaction do
+ transaction do
self << (object = attrs ? @reflection.klass.send(:with_scope, :create => attrs) { @reflection.create_association } : @reflection.create_association)
object
end
diff --git a/activerecord/lib/active_record/attribute_methods.rb b/activerecord/lib/active_record/attribute_methods.rb
index 0a1baff87d..e5486738f0 100644
--- a/activerecord/lib/active_record/attribute_methods.rb
+++ b/activerecord/lib/active_record/attribute_methods.rb
@@ -10,7 +10,7 @@ module ActiveRecord
base.attribute_types_cached_by_default = ATTRIBUTE_TYPES_CACHED_BY_DEFAULT
base.cattr_accessor :time_zone_aware_attributes, :instance_writer => false
base.time_zone_aware_attributes = false
- base.cattr_accessor :skip_time_zone_conversion_for_attributes, :instance_writer => false
+ base.class_inheritable_accessor :skip_time_zone_conversion_for_attributes, :instance_writer => false
base.skip_time_zone_conversion_for_attributes = []
end
@@ -232,6 +232,10 @@ module ActiveRecord
def method_missing(method_id, *args, &block)
method_name = method_id.to_s
+ if self.class.private_method_defined?(method_name)
+ raise NoMethodError("Attempt to call private method", method_name, args)
+ end
+
# If we haven't generated any methods yet, generate them, then
# see if we've created the method we're looking for.
if !self.class.generated_methods?
@@ -334,10 +338,12 @@ module ActiveRecord
# <tt>person.respond_to?(:name=)</tt>, and <tt>person.respond_to?(:name?)</tt>
# which will all return +true+.
alias :respond_to_without_attributes? :respond_to?
- def respond_to?(method, include_priv = false)
+ def respond_to?(method, include_private_methods = false)
method_name = method.to_s
if super
return true
+ elsif self.private_methods.include?(method_name) && !include_private_methods
+ return false
elsif !self.class.generated_methods?
self.class.define_attribute_methods
if self.class.generated_methods.include?(method_name)
diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb
index c0c9b8a9b3..ac15eed408 100755
--- a/activerecord/lib/active_record/base.rb
+++ b/activerecord/lib/active_record/base.rb
@@ -1632,19 +1632,19 @@ module ActiveRecord #:nodoc:
(safe_to_array(first) + safe_to_array(second)).uniq
end
- def merge_joins(first, second)
- if first.is_a?(String) && second.is_a?(String)
- "#{first} #{second}"
- elsif first.is_a?(String) || second.is_a?(String)
- if first.is_a?(String)
- join_dependency = ActiveRecord::Associations::ClassMethods::InnerJoinDependency.new(self, second, nil)
- "#{first} #{join_dependency.join_associations.collect { |assoc| assoc.association_join }.join}"
- else
- join_dependency = ActiveRecord::Associations::ClassMethods::InnerJoinDependency.new(self, first, nil)
- "#{join_dependency.join_associations.collect { |assoc| assoc.association_join }.join} #{second}"
+ def merge_joins(*joins)
+ if joins.any?{|j| j.is_a?(String) || array_of_strings?(j) }
+ joins = joins.collect do |join|
+ join = [join] if join.is_a?(String)
+ unless array_of_strings?(join)
+ join_dependency = ActiveRecord::Associations::ClassMethods::InnerJoinDependency.new(self, join, nil)
+ join = join_dependency.join_associations.collect { |assoc| assoc.association_join }
+ end
+ join
end
+ joins.flatten.uniq
else
- (safe_to_array(first) + safe_to_array(second)).uniq
+ joins.collect{|j| safe_to_array(j)}.flatten.uniq
end
end
@@ -1660,6 +1660,10 @@ module ActiveRecord #:nodoc:
end
end
+ def array_of_strings?(o)
+ o.is_a?(Array) && o.all?{|obj| obj.is_a?(String)}
+ end
+
def add_order!(sql, order, scope = :auto)
scope = scope(:find) if :auto == scope
scoped_order = scope[:order] if scope
@@ -1708,8 +1712,12 @@ module ActiveRecord #:nodoc:
merged_joins = scope && scope[:joins] && joins ? merge_joins(scope[:joins], joins) : (joins || scope && scope[:joins])
case merged_joins
when Symbol, Hash, Array
- join_dependency = ActiveRecord::Associations::ClassMethods::InnerJoinDependency.new(self, merged_joins, nil)
- sql << " #{join_dependency.join_associations.collect { |assoc| assoc.association_join }.join} "
+ if array_of_strings?(merged_joins)
+ sql << merged_joins.join(' ') + " "
+ else
+ join_dependency = ActiveRecord::Associations::ClassMethods::InnerJoinDependency.new(self, merged_joins, nil)
+ sql << " #{join_dependency.join_associations.collect { |assoc| assoc.association_join }.join} "
+ end
when String
sql << " #{merged_joins} "
end
@@ -2387,8 +2395,18 @@ module ActiveRecord #:nodoc:
# Deletes the record in the database and freezes this instance to reflect that no changes should
# be made (since they can't be persisted).
#
+ # Unlike #destroy, this method doesn't run any +before_delete+ and +after_delete+
+ # callbacks, nor will it enforce any association +:dependent+ rules.
+ #
# In addition to deleting this record, any defined +before_delete+ and +after_delete+
# callbacks are run, and +:dependent+ rules defined on associations are run.
+ def delete
+ self.class.delete(id) unless new_record?
+ freeze
+ end
+
+ # Deletes the record in the database and freezes this instance to reflect that no changes should
+ # be made (since they can't be persisted).
def destroy
unless new_record?
connection.delete <<-end_sql, "#{self.class.name} Destroy"
@@ -2828,7 +2846,7 @@ module ActiveRecord #:nodoc:
end
def instantiate_time_object(name, values)
- if self.class.time_zone_aware_attributes && !self.class.skip_time_zone_conversion_for_attributes.include?(name.to_sym)
+ if self.class.send(:create_time_zone_conversion_attribute?, name, column_for_attribute(name))
Time.zone.local(*values)
else
Time.time_with_datetime_fallback(@@default_timezone, *values)
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb
index 22304edfc9..58992f91da 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb
@@ -40,6 +40,10 @@ module ActiveRecord
type == :integer || type == :float || type == :decimal
end
+ def has_default?
+ !default.nil?
+ end
+
# Returns the Ruby class that corresponds to the abstract data type.
def klass
case type
diff --git a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb
index c2a0fb72bf..a26fd02b90 100644
--- a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb
@@ -80,7 +80,7 @@ module ActiveRecord
def extract_default(default)
if type == :binary || type == :text
if default.blank?
- nil
+ return null ? nil : ''
else
raise ArgumentError, "#{type} columns cannot have a default value: #{default.inspect}"
end
@@ -91,6 +91,11 @@ module ActiveRecord
end
end
+ def has_default?
+ return false if type == :binary || type == :text #mysql forbids defaults on blob and text columns
+ super
+ end
+
private
def simplified_type(field_type)
return :boolean if MysqlAdapter.emulate_booleans && field_type.downcase.index("tinyint(1)")
diff --git a/activerecord/lib/active_record/i18n_interpolation_deprecation.rb b/activerecord/lib/active_record/i18n_interpolation_deprecation.rb
new file mode 100644
index 0000000000..cd634e1b8d
--- /dev/null
+++ b/activerecord/lib/active_record/i18n_interpolation_deprecation.rb
@@ -0,0 +1,26 @@
+# Deprecates the use of the former message interpolation syntax in activerecord
+# as in "must have %d characters". The new syntax uses explicit variable names
+# as in "{{value}} must have {{count}} characters".
+
+require 'i18n/backend/simple'
+module I18n
+ module Backend
+ class Simple
+ DEPRECATED_INTERPOLATORS = { '%d' => '{{count}}', '%s' => '{{value}}' }
+
+ protected
+ def interpolate_with_deprecated_syntax(locale, string, values = {})
+ return string unless string.is_a?(String)
+
+ string = string.gsub(/%d|%s/) do |s|
+ instead = DEPRECATED_INTERPOLATORS[s]
+ ActiveSupport::Deprecation.warn "using #{s} in messages is deprecated; use #{instead} instead."
+ instead
+ end
+
+ interpolate_without_deprecated_syntax(locale, string, values)
+ end
+ alias_method_chain :interpolate, :deprecated_syntax
+ end
+ end
+end \ No newline at end of file
diff --git a/activerecord/lib/active_record/schema_dumper.rb b/activerecord/lib/active_record/schema_dumper.rb
index b90ed88c6b..4f96e225c1 100644
--- a/activerecord/lib/active_record/schema_dumper.rb
+++ b/activerecord/lib/active_record/schema_dumper.rb
@@ -102,7 +102,7 @@ HEADER
spec[:precision] = column.precision.inspect if !column.precision.nil?
spec[:scale] = column.scale.inspect if !column.scale.nil?
spec[:null] = 'false' if !column.null
- spec[:default] = default_string(column.default) if !column.default.nil?
+ spec[:default] = default_string(column.default) if column.has_default?
(spec.keys - [:name, :type]).each{ |k| spec[k].insert(0, "#{k.inspect} => ")}
spec
end.compact
diff --git a/activerecord/lib/active_record/validations.rb b/activerecord/lib/active_record/validations.rb
index 8481706074..9220eae4d1 100644
--- a/activerecord/lib/active_record/validations.rb
+++ b/activerecord/lib/active_record/validations.rb
@@ -472,7 +472,7 @@ module ActiveRecord
db_cols = begin
column_names
- rescue ActiveRecord::StatementInvalid
+ rescue Exception # To ignore both statement and connection errors
[]
end
names = attr_names.reject { |name| db_cols.include?(name.to_s) }
@@ -738,7 +738,7 @@ module ActiveRecord
condition_params = [value]
else
condition_sql = "LOWER(#{sql_attribute}) #{comparison_operator}"
- condition_params = [value.chars.downcase]
+ condition_params = [value.mb_chars.downcase]
end
if scope = configuration[:scope]
diff --git a/activerecord/lib/active_record/version.rb b/activerecord/lib/active_record/version.rb
index aaadef9979..2479b75789 100644
--- a/activerecord/lib/active_record/version.rb
+++ b/activerecord/lib/active_record/version.rb
@@ -1,7 +1,7 @@
module ActiveRecord
module VERSION #:nodoc:
MAJOR = 2
- MINOR = 1
+ MINOR = 2
TINY = 0
STRING = [MAJOR, MINOR, TINY].join('.')
diff --git a/activerecord/test/cases/associations/extension_test.rb b/activerecord/test/cases/associations/extension_test.rb
index 5c01c3c1f5..9390633d5b 100644
--- a/activerecord/test/cases/associations/extension_test.rb
+++ b/activerecord/test/cases/associations/extension_test.rb
@@ -3,6 +3,7 @@ require 'models/post'
require 'models/comment'
require 'models/project'
require 'models/developer'
+require 'models/company_in_module'
class AssociationsExtensionsTest < ActiveRecord::TestCase
fixtures :projects, :developers, :developers_projects, :comments, :posts
@@ -44,4 +45,18 @@ class AssociationsExtensionsTest < ActiveRecord::TestCase
david = Marshal.load(Marshal.dump(david))
assert_equal projects(:action_controller), david.projects_extended_by_name.find_most_recent
end
+
+
+ def test_extension_name
+ extension = Proc.new {}
+ name = :association_name
+
+ assert_equal 'DeveloperAssociationNameAssociationExtension', Developer.send(:create_extension_modules, name, extension, []).first.name
+ assert_equal 'MyApplication::Business::DeveloperAssociationNameAssociationExtension',
+MyApplication::Business::Developer.send(:create_extension_modules, name, extension, []).first.name
+ assert_equal 'MyApplication::Business::DeveloperAssociationNameAssociationExtension', MyApplication::Business::Developer.send(:create_extension_modules, name, extension, []).first.name
+ assert_equal 'MyApplication::Business::DeveloperAssociationNameAssociationExtension', MyApplication::Business::Developer.send(:create_extension_modules, name, extension, []).first.name
+ end
+
+
end
diff --git a/activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb b/activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb
index 9981f4c5d5..2949f1d304 100644
--- a/activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb
+++ b/activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb
@@ -253,7 +253,7 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase
assert !devel.projects.loaded?
assert_equal devel.projects.last, proj
- assert devel.projects.loaded?
+ assert !devel.projects.loaded?
assert !proj.new_record?
assert_equal Developer.find(1).projects.sort_by(&:id).last, proj # prove join table is updated
@@ -738,4 +738,13 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase
# Array#count in Ruby >=1.8.7, which would raise an ArgumentError
assert_nothing_raised { david.projects.count(:all, :conditions => '1=1') }
end
+
+ uses_mocha 'mocking Post.transaction' do
+ def test_association_proxy_transaction_method_starts_transaction_in_association_class
+ Post.expects(:transaction)
+ Category.find(:first).posts.transaction do
+ # nothing
+ end
+ end
+ end
end
diff --git a/activerecord/test/cases/associations/has_many_associations_test.rb b/activerecord/test/cases/associations/has_many_associations_test.rb
index 5bcbc5eb5b..315d77de07 100644
--- a/activerecord/test/cases/associations/has_many_associations_test.rb
+++ b/activerecord/test/cases/associations/has_many_associations_test.rb
@@ -249,7 +249,9 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
end
def test_find_scoped_grouped
+ assert_equal 1, companies(:first_firm).clients_grouped_by_firm_id.size
assert_equal 1, companies(:first_firm).clients_grouped_by_firm_id.length
+ assert_equal 2, companies(:first_firm).clients_grouped_by_name.size
assert_equal 2, companies(:first_firm).clients_grouped_by_name.length
end
@@ -1007,6 +1009,19 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
assert firm.clients.loaded?
end
+ def test_calling_first_or_last_on_existing_record_with_create_should_not_load_association
+ firm = companies(:first_firm)
+ firm.clients.create(:name => 'Foo')
+ assert !firm.clients.loaded?
+
+ assert_queries 2 do
+ firm.clients.first
+ firm.clients.last
+ end
+
+ assert !firm.clients.loaded?
+ end
+
def test_calling_first_or_last_on_new_record_should_not_run_queries
firm = Firm.new
@@ -1056,4 +1071,13 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
ActiveRecord::Base.store_full_sti_class = old
end
+ uses_mocha 'mocking Comment.transaction' do
+ def test_association_proxy_transaction_method_starts_transaction_in_association_class
+ Comment.expects(:transaction)
+ Post.find(:first).comments.transaction do
+ # nothing
+ end
+ end
+ end
+
end
diff --git a/activerecord/test/cases/associations/has_many_through_associations_test.rb b/activerecord/test/cases/associations/has_many_through_associations_test.rb
index 0be050ec81..12cce98c26 100644
--- a/activerecord/test/cases/associations/has_many_through_associations_test.rb
+++ b/activerecord/test/cases/associations/has_many_through_associations_test.rb
@@ -220,4 +220,13 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase
assert_equal [posts(:welcome).id, posts(:authorless).id].sort, person.post_ids.sort
assert !person.posts.loaded?
end
+
+ uses_mocha 'mocking Tag.transaction' do
+ def test_association_proxy_transaction_method_starts_transaction_in_association_class
+ Tag.expects(:transaction)
+ Post.find(:first).tags.transaction do
+ # nothing
+ end
+ end
+ end
end
diff --git a/activerecord/test/cases/associations_test.rb b/activerecord/test/cases/associations_test.rb
index 2050d16179..cde451de0e 100644
--- a/activerecord/test/cases/associations_test.rb
+++ b/activerecord/test/cases/associations_test.rb
@@ -194,6 +194,14 @@ class AssociationProxyTest < ActiveRecord::TestCase
assert_equal david, welcome.author
end
+ def test_assigning_association_id_after_reload
+ welcome = posts(:welcome)
+ welcome.reload
+ assert_nothing_raised do
+ welcome.author_id = authors(:david).id
+ end
+ end
+
def test_reload_returns_assocition
david = developers(:david)
assert_nothing_raised do
diff --git a/activerecord/test/cases/attribute_methods_test.rb b/activerecord/test/cases/attribute_methods_test.rb
index 7999e29264..160716f944 100644
--- a/activerecord/test/cases/attribute_methods_test.rb
+++ b/activerecord/test/cases/attribute_methods_test.rb
@@ -1,5 +1,6 @@
require "cases/helper"
require 'models/topic'
+require 'models/minimalistic'
class AttributeMethodsTest < ActiveRecord::TestCase
fixtures :topics
@@ -57,19 +58,19 @@ class AttributeMethodsTest < ActiveRecord::TestCase
def test_kernel_methods_not_implemented_in_activerecord
%w(test name display y).each do |method|
- assert_equal false, ActiveRecord::Base.instance_method_already_implemented?(method), "##{method} is defined"
+ assert !ActiveRecord::Base.instance_method_already_implemented?(method), "##{method} is defined"
end
end
def test_primary_key_implemented
- assert_equal true, Class.new(ActiveRecord::Base).instance_method_already_implemented?('id')
+ assert Class.new(ActiveRecord::Base).instance_method_already_implemented?('id')
end
def test_defined_kernel_methods_implemented_in_model
%w(test name display y).each do |method|
klass = Class.new ActiveRecord::Base
klass.class_eval "def #{method}() 'defined #{method}' end"
- assert_equal true, klass.instance_method_already_implemented?(method), "##{method} is not defined"
+ assert klass.instance_method_already_implemented?(method), "##{method} is not defined"
end
end
@@ -79,7 +80,7 @@ class AttributeMethodsTest < ActiveRecord::TestCase
abstract.class_eval "def #{method}() 'defined #{method}' end"
abstract.abstract_class = true
klass = Class.new abstract
- assert_equal true, klass.instance_method_already_implemented?(method), "##{method} is not defined"
+ assert klass.instance_method_already_implemented?(method), "##{method} is not defined"
end
end
@@ -219,6 +220,48 @@ class AttributeMethodsTest < ActiveRecord::TestCase
end
end
+ def test_setting_time_zone_conversion_for_attributes_should_write_value_on_class_variable
+ Topic.skip_time_zone_conversion_for_attributes = [:field_a]
+ Minimalistic.skip_time_zone_conversion_for_attributes = [:field_b]
+
+ assert_equal [:field_a], Topic.skip_time_zone_conversion_for_attributes
+ assert_equal [:field_b], Minimalistic.skip_time_zone_conversion_for_attributes
+ end
+
+ def test_read_attributes_respect_access_control
+ privatize("title")
+
+ topic = @target.new(:title => "The pros and cons of programming naked.")
+ assert !topic.respond_to?(:title)
+ assert_raise(NoMethodError) { topic.title }
+ topic.send(:title)
+ end
+
+ def test_write_attributes_respect_access_control
+ privatize("title=(value)")
+
+ topic = @target.new
+ assert !topic.respond_to?(:title=)
+ assert_raise(NoMethodError) { topic.title = "Pants"}
+ topic.send(:title=, "Very large pants")
+ end
+
+ def test_question_attributes_respect_access_control
+ privatize("title?")
+
+ topic = @target.new(:title => "Isaac Newton's pants")
+ assert !topic.respond_to?(:title?)
+ assert_raise(NoMethodError) { topic.title? }
+ assert topic.send(:title?)
+ end
+
+ def test_bulk_update_respects_access_control
+ privatize("title=(value)")
+
+ assert_raise(ActiveRecord::UnknownAttributeError) { topic = @target.new(:title => "Rants about pants") }
+ assert_raise(ActiveRecord::UnknownAttributeError) { @target.new.attributes = { :title => "Ants in pants" } }
+ end
+
private
def time_related_columns_on_topic
Topic.columns.select{|c| [:time, :date, :datetime, :timestamp].include?(c.type)}.map(&:name)
@@ -235,4 +278,13 @@ class AttributeMethodsTest < ActiveRecord::TestCase
Time.zone = old_zone
ActiveRecord::Base.time_zone_aware_attributes = old_tz
end
+
+ def privatize(method_signature)
+ @target.class_eval <<-private_method
+ private
+ def #{method_signature}
+ "I'm private"
+ end
+ private_method
+ end
end
diff --git a/activerecord/test/cases/base_test.rb b/activerecord/test/cases/base_test.rb
index bda6f346f0..d512834237 100644..100755
--- a/activerecord/test/cases/base_test.rb
+++ b/activerecord/test/cases/base_test.rb
@@ -472,6 +472,18 @@ class BasicsTest < ActiveRecord::TestCase
assert topic.instance_variable_get("@custom_approved")
end
+ def test_delete
+ topic = Topic.find(1)
+ assert_equal topic, topic.delete, 'topic.delete did not return self'
+ assert topic.frozen?, 'topic not frozen after delete'
+ assert_raise(ActiveRecord::RecordNotFound) { Topic.find(topic.id) }
+ end
+
+ def test_delete_doesnt_run_callbacks
+ Topic.find(1).delete
+ assert_not_nil Topic.find(2)
+ end
+
def test_destroy
topic = Topic.find(1)
assert_equal topic, topic.destroy, 'topic.destroy did not return self'
@@ -820,6 +832,20 @@ class BasicsTest < ActiveRecord::TestCase
assert_equal [ Topic.find(1) ], [ Topic.find(2).topic ] & [ Topic.find(1) ]
end
+ def test_delete_new_record
+ client = Client.new
+ client.delete
+ assert client.frozen?
+ end
+
+ def test_delete_record_with_associations
+ client = Client.find(3)
+ client.delete
+ assert client.frozen?
+ assert_kind_of Firm, client.firm
+ assert_raises(ActiveSupport::FrozenObjectError) { client.name = "something else" }
+ end
+
def test_destroy_new_record
client = Client.new
client.destroy
@@ -1084,6 +1110,24 @@ class BasicsTest < ActiveRecord::TestCase
Time.zone = nil
Topic.skip_time_zone_conversion_for_attributes = []
end
+
+ def test_multiparameter_attributes_on_time_only_column_with_time_zone_aware_attributes_does_not_do_time_zone_conversion
+ ActiveRecord::Base.time_zone_aware_attributes = true
+ ActiveRecord::Base.default_timezone = :utc
+ Time.zone = ActiveSupport::TimeZone[-28800]
+ attributes = {
+ "bonus_time(1i)" => "2000", "bonus_time(2i)" => "1", "bonus_time(3i)" => "1",
+ "bonus_time(4i)" => "16", "bonus_time(5i)" => "24"
+ }
+ topic = Topic.find(1)
+ topic.attributes = attributes
+ assert_equal Time.utc(2000, 1, 1, 16, 24, 0), topic.bonus_time
+ assert topic.bonus_time.utc?
+ ensure
+ ActiveRecord::Base.time_zone_aware_attributes = false
+ ActiveRecord::Base.default_timezone = :local
+ Time.zone = nil
+ end
def test_multiparameter_attributes_on_time_with_empty_seconds
attributes = {
@@ -1420,15 +1464,17 @@ class BasicsTest < ActiveRecord::TestCase
if RUBY_VERSION < '1.9'
def test_quote_chars
- str = 'The Narrator'
- topic = Topic.create(:author_name => str)
- assert_equal str, topic.author_name
+ with_kcode('UTF8') do
+ str = 'The Narrator'
+ topic = Topic.create(:author_name => str)
+ assert_equal str, topic.author_name
- assert_kind_of ActiveSupport::Multibyte::Chars, str.chars
- topic = Topic.find_by_author_name(str.chars)
+ assert_kind_of ActiveSupport::Multibyte.proxy_class, str.mb_chars
+ topic = Topic.find_by_author_name(str.mb_chars)
- assert_kind_of Topic, topic
- assert_equal str, topic.author_name, "The right topic should have been found by name even with name passed as Chars"
+ assert_kind_of Topic, topic
+ assert_equal str, topic.author_name, "The right topic should have been found by name even with name passed as Chars"
+ end
end
end
@@ -2021,4 +2067,18 @@ class BasicsTest < ActiveRecord::TestCase
ensure
ActiveRecord::Base.logger = original_logger
end
+
+ private
+ def with_kcode(kcode)
+ if RUBY_VERSION < '1.9'
+ orig_kcode, $KCODE = $KCODE, kcode
+ begin
+ yield
+ ensure
+ $KCODE = orig_kcode
+ end
+ else
+ yield
+ end
+ end
end
diff --git a/activerecord/test/cases/defaults_test.rb b/activerecord/test/cases/defaults_test.rb
index 3473b846a0..ee84cb8af8 100644
--- a/activerecord/test/cases/defaults_test.rb
+++ b/activerecord/test/cases/defaults_test.rb
@@ -19,6 +19,37 @@ class DefaultTest < ActiveRecord::TestCase
end
if current_adapter?(:MysqlAdapter)
+
+ #MySQL 5 and higher is quirky with not null text/blob columns.
+ #With MySQL Text/blob columns cannot have defaults. If the column is not null MySQL will report that the column has a null default
+ #but it behaves as though the column had a default of ''
+ def test_mysql_text_not_null_defaults
+ klass = Class.new(ActiveRecord::Base)
+ klass.table_name = 'test_mysql_text_not_null_defaults'
+ klass.connection.create_table klass.table_name do |t|
+ t.column :non_null_text, :text, :null => false
+ t.column :non_null_blob, :blob, :null => false
+ t.column :null_text, :text, :null => true
+ t.column :null_blob, :blob, :null => true
+ end
+ assert_equal '', klass.columns_hash['non_null_blob'].default
+ assert_equal '', klass.columns_hash['non_null_text'].default
+
+ assert_equal nil, klass.columns_hash['null_blob'].default
+ assert_equal nil, klass.columns_hash['null_text'].default
+
+ assert_nothing_raised do
+ instance = klass.create!
+ assert_equal '', instance.non_null_text
+ assert_equal '', instance.non_null_blob
+ assert_nil instance.null_text
+ assert_nil instance.null_blob
+ end
+ ensure
+ klass.connection.drop_table(klass.table_name) rescue nil
+ end
+
+
# MySQL uses an implicit default 0 rather than NULL unless in strict mode.
# We use an implicit NULL so schema.rb is compatible with other databases.
def test_mysql_integer_not_null_defaults
diff --git a/activerecord/test/cases/finder_test.rb b/activerecord/test/cases/finder_test.rb
index cbdff382fe..292b88edbc 100644
--- a/activerecord/test/cases/finder_test.rb
+++ b/activerecord/test/cases/finder_test.rb
@@ -465,8 +465,8 @@ class FinderTest < ActiveRecord::TestCase
quoted_bambi_and_thumper = ActiveRecord::Base.connection.quote("Bambi\nand\nThumper")
assert_equal "name=#{quoted_bambi}", bind('name=?', "Bambi")
assert_equal "name=#{quoted_bambi_and_thumper}", bind('name=?', "Bambi\nand\nThumper")
- assert_equal "name=#{quoted_bambi}", bind('name=?', "Bambi".chars)
- assert_equal "name=#{quoted_bambi_and_thumper}", bind('name=?', "Bambi\nand\nThumper".chars)
+ assert_equal "name=#{quoted_bambi}", bind('name=?', "Bambi".mb_chars)
+ assert_equal "name=#{quoted_bambi_and_thumper}", bind('name=?', "Bambi\nand\nThumper".mb_chars)
end
def test_bind_record
@@ -935,6 +935,17 @@ class FinderTest < ActiveRecord::TestCase
assert_equal 1, first.id
end
+ def test_joins_with_string_array
+ person_with_reader_and_post = Post.find(
+ :all,
+ :joins => [
+ "INNER JOIN categorizations ON categorizations.post_id = posts.id",
+ "INNER JOIN categories ON categories.id = categorizations.category_id AND categories.type = 'SpecialCategory'"
+ ]
+ )
+ assert_equal 1, person_with_reader_and_post.size
+ end
+
def test_find_by_id_with_conditions_with_or
assert_nothing_raised do
Post.find([1,2,3],
diff --git a/activerecord/test/cases/helper.rb b/activerecord/test/cases/helper.rb
index f30d58546e..f7bdac8013 100644
--- a/activerecord/test/cases/helper.rb
+++ b/activerecord/test/cases/helper.rb
@@ -46,3 +46,17 @@ end
class << ActiveRecord::Base
public :with_scope, :with_exclusive_scope
end
+
+unless ENV['FIXTURE_DEBUG']
+ module Test #:nodoc:
+ module Unit #:nodoc:
+ class << TestCase #:nodoc:
+ def try_to_load_dependency_with_silence(*args)
+ ActiveRecord::Base.logger.silence { try_to_load_dependency_without_silence(*args)}
+ end
+
+ alias_method_chain :try_to_load_dependency, :silence
+ end
+ end
+ end
+end \ No newline at end of file
diff --git a/activerecord/test/cases/method_scoping_test.rb b/activerecord/test/cases/method_scoping_test.rb
index af6fcd32ad..ff10bfaf3e 100644
--- a/activerecord/test/cases/method_scoping_test.rb
+++ b/activerecord/test/cases/method_scoping_test.rb
@@ -138,6 +138,36 @@ class MethodScopingTest < ActiveRecord::TestCase
assert_equal authors(:david).attributes, scoped_authors.first.attributes
end
+ def test_scoped_find_merges_string_array_style_and_string_style_joins
+ scoped_authors = Author.with_scope(:find => { :joins => ["INNER JOIN posts ON posts.author_id = authors.id"]}) do
+ Author.find(:all, :select => 'DISTINCT authors.*', :joins => 'INNER JOIN comments ON posts.id = comments.post_id', :conditions => 'comments.id = 1')
+ end
+ assert scoped_authors.include?(authors(:david))
+ assert !scoped_authors.include?(authors(:mary))
+ assert_equal 1, scoped_authors.size
+ assert_equal authors(:david).attributes, scoped_authors.first.attributes
+ end
+
+ def test_scoped_find_merges_string_array_style_and_hash_style_joins
+ scoped_authors = Author.with_scope(:find => { :joins => :posts}) do
+ Author.find(:all, :select => 'DISTINCT authors.*', :joins => ['INNER JOIN comments ON posts.id = comments.post_id'], :conditions => 'comments.id = 1')
+ end
+ assert scoped_authors.include?(authors(:david))
+ assert !scoped_authors.include?(authors(:mary))
+ assert_equal 1, scoped_authors.size
+ assert_equal authors(:david).attributes, scoped_authors.first.attributes
+ end
+
+ def test_scoped_find_merges_joins_and_eliminates_duplicate_string_joins
+ scoped_authors = Author.with_scope(:find => { :joins => 'INNER JOIN posts ON posts.author_id = authors.id'}) do
+ Author.find(:all, :select => 'DISTINCT authors.*', :joins => ["INNER JOIN posts ON posts.author_id = authors.id", "INNER JOIN comments ON posts.id = comments.post_id"], :conditions => 'comments.id = 1')
+ end
+ assert scoped_authors.include?(authors(:david))
+ assert !scoped_authors.include?(authors(:mary))
+ assert_equal 1, scoped_authors.size
+ assert_equal authors(:david).attributes, scoped_authors.first.attributes
+ end
+
def test_scoped_count_include
# with the include, will retrieve only developers for the given project
Developer.with_scope(:find => { :include => :projects }) do
diff --git a/activerecord/test/cases/migration_test.rb b/activerecord/test/cases/migration_test.rb
index c1a8da2270..ac44dd7ffe 100644
--- a/activerecord/test/cases/migration_test.rb
+++ b/activerecord/test/cases/migration_test.rb
@@ -1133,7 +1133,11 @@ if ActiveRecord::Base.connection.supports_migrations?
columns = Person.connection.columns(:binary_testings)
data_column = columns.detect { |c| c.name == "data" }
- assert_nil data_column.default
+ if current_adapter?(:MysqlAdapter)
+ assert_equal '', data_column.default
+ else
+ assert_nil data_column.default
+ end
Person.connection.drop_table :binary_testings rescue nil
end
diff --git a/activerecord/test/cases/named_scope_test.rb b/activerecord/test/cases/named_scope_test.rb
index 444debd255..64e899780c 100644
--- a/activerecord/test/cases/named_scope_test.rb
+++ b/activerecord/test/cases/named_scope_test.rb
@@ -271,4 +271,10 @@ class NamedScopeTest < ActiveRecord::TestCase
topics.size # use loaded (no query)
end
end
+
+ def test_chaining_with_duplicate_joins
+ join = "INNER JOIN comments ON comments.post_id = posts.id"
+ post = Post.find(1)
+ assert_equal post.comments.size, Post.scoped(:joins => join).scoped(:joins => join, :conditions => "posts.id = #{post.id}").size
+ end
end
diff --git a/activerecord/test/cases/sanitize_test.rb b/activerecord/test/cases/sanitize_test.rb
index 0106572ced..817897ceac 100644
--- a/activerecord/test/cases/sanitize_test.rb
+++ b/activerecord/test/cases/sanitize_test.rb
@@ -8,18 +8,18 @@ class SanitizeTest < ActiveRecord::TestCase
def test_sanitize_sql_array_handles_string_interpolation
quoted_bambi = ActiveRecord::Base.connection.quote_string("Bambi")
assert_equal "name=#{quoted_bambi}", Binary.send(:sanitize_sql_array, ["name=%s", "Bambi"])
- assert_equal "name=#{quoted_bambi}", Binary.send(:sanitize_sql_array, ["name=%s", "Bambi".chars])
+ assert_equal "name=#{quoted_bambi}", Binary.send(:sanitize_sql_array, ["name=%s", "Bambi".mb_chars])
quoted_bambi_and_thumper = ActiveRecord::Base.connection.quote_string("Bambi\nand\nThumper")
assert_equal "name=#{quoted_bambi_and_thumper}",Binary.send(:sanitize_sql_array, ["name=%s", "Bambi\nand\nThumper"])
- assert_equal "name=#{quoted_bambi_and_thumper}",Binary.send(:sanitize_sql_array, ["name=%s", "Bambi\nand\nThumper".chars])
+ assert_equal "name=#{quoted_bambi_and_thumper}",Binary.send(:sanitize_sql_array, ["name=%s", "Bambi\nand\nThumper".mb_chars])
end
def test_sanitize_sql_array_handles_bind_variables
quoted_bambi = ActiveRecord::Base.connection.quote("Bambi")
assert_equal "name=#{quoted_bambi}", Binary.send(:sanitize_sql_array, ["name=?", "Bambi"])
- assert_equal "name=#{quoted_bambi}", Binary.send(:sanitize_sql_array, ["name=?", "Bambi".chars])
+ assert_equal "name=#{quoted_bambi}", Binary.send(:sanitize_sql_array, ["name=?", "Bambi".mb_chars])
quoted_bambi_and_thumper = ActiveRecord::Base.connection.quote("Bambi\nand\nThumper")
assert_equal "name=#{quoted_bambi_and_thumper}", Binary.send(:sanitize_sql_array, ["name=?", "Bambi\nand\nThumper"])
- assert_equal "name=#{quoted_bambi_and_thumper}", Binary.send(:sanitize_sql_array, ["name=?", "Bambi\nand\nThumper".chars])
+ assert_equal "name=#{quoted_bambi_and_thumper}", Binary.send(:sanitize_sql_array, ["name=?", "Bambi\nand\nThumper".mb_chars])
end
end
diff --git a/activerecord/test/cases/validations_i18n_test.rb b/activerecord/test/cases/validations_i18n_test.rb
index e34890ef19..42246f18b6 100644
--- a/activerecord/test/cases/validations_i18n_test.rb
+++ b/activerecord/test/cases/validations_i18n_test.rb
@@ -6,12 +6,16 @@ class ActiveRecordValidationsI18nTests < Test::Unit::TestCase
def setup
reset_callbacks Topic
@topic = Topic.new
+ @old_load_path, @old_backend = I18n.load_path, I18n.backend
+ I18n.load_path.clear
+ I18n.backend = I18n::Backend::Simple.new
I18n.backend.store_translations('en-US', :activerecord => {:errors => {:messages => {:custom => nil}}})
end
def teardown
reset_callbacks Topic
- I18n.load_translations File.dirname(__FILE__) + '/../../lib/active_record/locale/en-US.yml'
+ I18n.load_path.replace @old_load_path
+ I18n.backend = @old_backend
end
def unique_topic