aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord
diff options
context:
space:
mode:
authorXavier Noria <fxn@hashref.com>2010-03-31 07:47:58 -0700
committerXavier Noria <fxn@hashref.com>2010-03-31 07:47:58 -0700
commit824fa10f4d1306cc1e310a7d5de7e95cfb07d6f8 (patch)
tree1967c2a945d6e131d467fb4f0178a0f60e01ae8a /activerecord
parent1ed1652bef981d9402797b6cb9f0920a40eea21a (diff)
parentdb28d407f76a790a31e27bf51560e23425dd6944 (diff)
downloadrails-824fa10f4d1306cc1e310a7d5de7e95cfb07d6f8.tar.gz
rails-824fa10f4d1306cc1e310a7d5de7e95cfb07d6f8.tar.bz2
rails-824fa10f4d1306cc1e310a7d5de7e95cfb07d6f8.zip
Merge commit 'rails/master'
Diffstat (limited to 'activerecord')
-rw-r--r--activerecord/CHANGELOG6
-rw-r--r--activerecord/lib/active_record.rb6
-rw-r--r--activerecord/lib/active_record/association_preload.rb7
-rwxr-xr-xactiverecord/lib/active_record/associations.rb42
-rw-r--r--activerecord/lib/active_record/associations/has_many_through_association.rb1
-rw-r--r--activerecord/lib/active_record/attribute_methods/dirty.rb2
-rw-r--r--activerecord/lib/active_record/attribute_methods/primary_key.rb22
-rw-r--r--activerecord/lib/active_record/attribute_methods/query.rb2
-rwxr-xr-xactiverecord/lib/active_record/base.rb18
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/query_cache.rb2
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb1
-rw-r--r--activerecord/lib/active_record/connection_adapters/mysql_adapter.rb1
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb13
-rw-r--r--activerecord/lib/active_record/fixtures.rb1
-rw-r--r--activerecord/lib/active_record/named_scope.rb13
-rw-r--r--activerecord/lib/active_record/nested_attributes.rb1
-rw-r--r--activerecord/lib/active_record/query_cache.rb2
-rw-r--r--activerecord/lib/active_record/railtie.rb16
-rw-r--r--activerecord/lib/active_record/relation.rb2
-rw-r--r--activerecord/lib/active_record/relation/batches.rb8
-rw-r--r--activerecord/lib/active_record/relation/calculations.rb2
-rw-r--r--activerecord/lib/active_record/relation/finder_methods.rb2
-rw-r--r--activerecord/lib/active_record/relation/predicate_builder.rb7
-rw-r--r--activerecord/lib/active_record/relation/query_methods.rb2
-rw-r--r--activerecord/lib/active_record/relation/spawn_methods.rb2
-rw-r--r--activerecord/lib/active_record/schema.rb2
-rw-r--r--activerecord/lib/active_record/validations/uniqueness.rb6
-rw-r--r--activerecord/test/cases/associations/belongs_to_associations_test.rb26
-rw-r--r--activerecord/test/cases/associations/eager_test.rb6
-rw-r--r--activerecord/test/cases/associations/has_many_associations_test.rb8
-rw-r--r--activerecord/test/cases/associations/has_one_associations_test.rb10
-rw-r--r--activerecord/test/cases/batches_test.rb16
-rw-r--r--activerecord/test/cases/modules_test.rb28
-rw-r--r--activerecord/test/cases/named_scope_test.rb23
-rw-r--r--activerecord/test/cases/pk_test.rb6
-rw-r--r--activerecord/test/models/company.rb5
-rw-r--r--activerecord/test/models/company_in_module.rb17
37 files changed, 270 insertions, 64 deletions
diff --git a/activerecord/CHANGELOG b/activerecord/CHANGELOG
index 214ec8c1d8..e379f4f967 100644
--- a/activerecord/CHANGELOG
+++ b/activerecord/CHANGELOG
@@ -1,9 +1,11 @@
-*Edge*
+*Rails 3.0.0 [Beta 2] (pending)*
+
+* To prefix the table names of all models in a module, define self.table_name_prefix on the module. #4032 [Andrew White]
* Silenced "SHOW FIELDS" and "SET SQL_AUTO_IS_NULL=0" statements from the MySQL driver to improve log signal to noise ration in development [DHH]
-*Rails 3.0 [Beta] (February 4th, 2010)*
+*Rails 3.0.0 [Beta 1] (February 4th, 2010)*
* PostgreSQLAdapter: set time_zone to UTC when Base.default_timezone == :utc so that Postgres doesn't incorrectly offset-adjust values inserted into TIMESTAMP WITH TIME ZONE columns. #3777 [Jack Christensen]
diff --git a/activerecord/lib/active_record.rb b/activerecord/lib/active_record.rb
index 5942640c85..8a1aa50e24 100644
--- a/activerecord/lib/active_record.rb
+++ b/activerecord/lib/active_record.rb
@@ -111,10 +111,10 @@ module ActiveRecord
autoload :TestCase
autoload :TestFixtures, 'active_record/fixtures'
+end
- base_hook do
- Arel::Table.engine = Arel::Sql::Engine.new(self)
- end
+ActiveSupport.on_load(:active_record) do
+ Arel::Table.engine = Arel::Sql::Engine.new(self)
end
I18n.load_path << File.dirname(__FILE__) + '/active_record/locale/en.yml' \ No newline at end of file
diff --git a/activerecord/lib/active_record/association_preload.rb b/activerecord/lib/active_record/association_preload.rb
index 6725d4e88b..95bbaf00cf 100644
--- a/activerecord/lib/active_record/association_preload.rb
+++ b/activerecord/lib/active_record/association_preload.rb
@@ -159,6 +159,11 @@ module ActiveRecord
association_proxy.__send__(:set_inverse_instance, associated_record, mapped_record)
end
end
+
+ id_to_record_map.each do |id, records|
+ next if seen_keys.include?(id.to_s)
+ records.each {|record| record.send("set_#{reflection_name}_target", nil) }
+ end
end
# Given a collection of ActiveRecord objects, constructs a Hash which maps
@@ -324,7 +329,7 @@ module ActiveRecord
klass = klass_name.constantize
table_name = klass.quoted_table_name
- primary_key = klass.primary_key
+ primary_key = reflection.options[:primary_key] || klass.primary_key
column_type = klass.columns.detect{|c| c.name == primary_key}.type
ids = id_map.keys.map do |id|
diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb
index d623ddb915..7406daf837 100755
--- a/activerecord/lib/active_record/associations.rb
+++ b/activerecord/lib/active_record/associations.rb
@@ -1,5 +1,6 @@
require 'active_support/core_ext/module/delegation'
require 'active_support/core_ext/enumerable'
+require 'active_support/core_ext/object/blank'
module ActiveRecord
class InverseOfAssociationNotFoundError < ActiveRecordError #:nodoc:
@@ -85,6 +86,15 @@ module ActiveRecord
end
end
+ # This error is raised when trying to destroy a parent instance in a N:1, 1:1 assosications
+ # (has_many, has_one) when there is at least 1 child assosociated instance.
+ # ex: if @project.tasks.size > 0, DeleteRestrictionError will be raised when trying to destroy @project
+ class DeleteRestrictionError < ActiveRecordError #:nodoc:
+ def initialize(reflection)
+ super("Cannot delete record because of dependent #{reflection.name}")
+ end
+ end
+
# See ActiveRecord::Associations::ClassMethods for documentation.
module Associations # :nodoc:
extend ActiveSupport::Concern
@@ -830,6 +840,8 @@ module ActiveRecord
# objects are deleted *without* calling their +destroy+ method. If set to <tt>:nullify</tt> all associated
# objects' foreign keys are set to +NULL+ *without* calling their +save+ callbacks. *Warning:* This option is ignored when also using
# the <tt>:through</tt> option.
+ # the <tt>:through</tt> option. If set to <tt>:restrict</tt>
+ # this object cannot be deleted if it has any associated object.
# [:finder_sql]
# Specify a complete SQL statement to fetch the association. This is a good way to go for complex
# associations that depend on multiple tables. Note: When this option is used, +find_in_collection+ is _not_ added.
@@ -1468,9 +1480,15 @@ module ActiveRecord
# Creates before_destroy callback methods that nullify, delete or destroy
# has_many associated objects, according to the defined :dependent rule.
+ # If the association is marked as :dependent => :restrict, create a callback
+ # that prevents deleting entirely.
#
# See HasManyAssociation#delete_records. Dependent associations
# delete children, otherwise foreign key is set to NULL.
+ # See HasManyAssociation#delete_records. Dependent associations
+ # delete children if the option is set to :destroy or :delete_all, set the
+ # foreign key to NULL if the option is set to :nullify, and do not touch the
+ # child records if the option is set to :restrict.
#
# The +extra_conditions+ parameter, which is not used within the main
# Active Record codebase, is meant to allow plugins to define extra
@@ -1530,14 +1548,24 @@ module ActiveRecord
%@#{dependent_conditions}@)
end
CALLBACK
+ when :restrict
+ method_name = "has_many_dependent_restrict_for_#{reflection.name}".to_sym
+ define_method(method_name) do
+ unless send(reflection.name).empty?
+ raise DeleteRestrictionError.new(reflection)
+ end
+ end
+ before_destroy method_name
else
- raise ArgumentError, "The :dependent option expects either :destroy, :delete_all, or :nullify (#{reflection.options[:dependent].inspect})"
+ raise ArgumentError, "The :dependent option expects either :destroy, :delete_all, :nullify or :restrict (#{reflection.options[:dependent].inspect})"
end
end
end
# Creates before_destroy callback methods that nullify, delete or destroy
# has_one associated objects, according to the defined :dependent rule.
+ # If the association is marked as :dependent => :restrict, create a callback
+ # that prevents deleting entirely.
def configure_dependency_for_has_one(reflection)
if reflection.options.include?(:dependent)
name = reflection.options[:dependent]
@@ -1558,8 +1586,16 @@ module ActiveRecord
association.update_attribute(#{reflection.primary_key_name.inspect}, nil) if association
end
eoruby
+ when :restrict
+ method_name = "has_one_dependent_restrict_for_#{reflection.name}".to_sym
+ define_method(method_name) do
+ unless send(reflection.name).nil?
+ raise DeleteRestrictionError.new(reflection)
+ end
+ end
+ before_destroy method_name
else
- raise ArgumentError, "The :dependent option expects either :destroy, :delete or :nullify (#{reflection.options[:dependent].inspect})"
+ raise ArgumentError, "The :dependent option expects either :destroy, :delete, :nullify or :restrict (#{reflection.options[:dependent].inspect})"
end
before_destroy method_name
@@ -1995,7 +2031,7 @@ module ActiveRecord
[aliased_table[foreign_key].eq(parent_table[reflection.options[:primary_key] || parent.primary_key])]
end
when :belongs_to
- [aliased_table[reflection.klass.primary_key].eq(parent_table[options[:foreign_key] || reflection.primary_key_name])]
+ [aliased_table[options[:primary_key] || reflection.klass.primary_key].eq(parent_table[options[:foreign_key] || reflection.primary_key_name])]
end
unless klass.descends_from_active_record?
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 bd2acd4340..5338bb099d 100644
--- a/activerecord/lib/active_record/associations/has_many_through_association.rb
+++ b/activerecord/lib/active_record/associations/has_many_through_association.rb
@@ -1,4 +1,5 @@
require "active_record/associations/through_association_scope"
+require 'active_support/core_ext/object/blank'
module ActiveRecord
module Associations
diff --git a/activerecord/lib/active_record/attribute_methods/dirty.rb b/activerecord/lib/active_record/attribute_methods/dirty.rb
index a8698a2f5a..435aea9b09 100644
--- a/activerecord/lib/active_record/attribute_methods/dirty.rb
+++ b/activerecord/lib/active_record/attribute_methods/dirty.rb
@@ -1,3 +1,5 @@
+require 'active_support/core_ext/object/blank'
+
module ActiveRecord
module AttributeMethods
module Dirty
diff --git a/activerecord/lib/active_record/attribute_methods/primary_key.rb b/activerecord/lib/active_record/attribute_methods/primary_key.rb
index 095814b635..411330dda2 100644
--- a/activerecord/lib/active_record/attribute_methods/primary_key.rb
+++ b/activerecord/lib/active_record/attribute_methods/primary_key.rb
@@ -3,6 +3,12 @@ module ActiveRecord
module PrimaryKey
extend ActiveSupport::Concern
+ # Returns this record's primary key value wrapped in an Array
+ # or nil if the record is a new_record?
+ def to_key
+ new_record? ? nil : [ send(self.class.primary_key) ]
+ end
+
module ClassMethods
# Defines the primary key field -- can be overridden in subclasses. Overwriting will negate any effect of the
# primary_key_prefix_type setting, though.
@@ -39,22 +45,6 @@ module ActiveRecord
end
alias :primary_key= :set_primary_key
end
-
- module InstanceMethods
-
- # Returns this record's primary key value wrapped in an Array
- # or nil if the record is a new_record?
- # This is done to comply with the AMo interface that expects
- # every AMo compliant object to respond_to?(:to_key) and return
- # an Enumerable object from that call, or nil if new_record?
- # This method also takes custom primary keys specified via
- # the +set_primary_key+ into account.
- def to_key
- new_record? ? nil : [ self.primary_key ]
- end
-
- end
-
end
end
end
diff --git a/activerecord/lib/active_record/attribute_methods/query.rb b/activerecord/lib/active_record/attribute_methods/query.rb
index a949d80120..948809c65a 100644
--- a/activerecord/lib/active_record/attribute_methods/query.rb
+++ b/activerecord/lib/active_record/attribute_methods/query.rb
@@ -1,3 +1,5 @@
+require 'active_support/core_ext/object/blank'
+
module ActiveRecord
module AttributeMethods
module Query
diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb
index 1c93346a52..37b379af9e 100755
--- a/activerecord/lib/active_record/base.rb
+++ b/activerecord/lib/active_record/base.rb
@@ -13,6 +13,8 @@ require 'active_support/core_ext/hash/slice'
require 'active_support/core_ext/string/behavior'
require 'active_support/core_ext/object/singleton_class'
require 'active_support/core_ext/module/delegation'
+require 'active_support/core_ext/object/duplicable'
+require 'active_support/core_ext/object/blank'
require 'arel'
require 'active_record/errors'
@@ -336,6 +338,9 @@ module ActiveRecord #:nodoc:
# Accessor for the name of the prefix string to prepend to every table name. So if set to "basecamp_", all
# table names will be named like "basecamp_projects", "basecamp_people", etc. This is a convenient way of creating a namespace
# for tables in a shared database. By default, the prefix is the empty string.
+ #
+ # If you are organising your models within modules you can add a prefix to the models within a namespace by defining
+ # a singleton method in the parent module called table_name_prefix which returns your chosen prefix.
cattr_accessor :table_name_prefix, :instance_writer => false
@@table_name_prefix = ""
@@ -763,7 +768,7 @@ module ActiveRecord #:nodoc:
contained = contained.singularize if parent.pluralize_table_names
contained << '_'
end
- name = "#{table_name_prefix}#{contained}#{undecorated_table_name(base.name)}#{table_name_suffix}"
+ name = "#{full_table_name_prefix}#{contained}#{undecorated_table_name(base.name)}#{table_name_suffix}"
end
@quoted_table_name = nil
@@ -771,6 +776,10 @@ module ActiveRecord #:nodoc:
name
end
+ def full_table_name_prefix #:nodoc:
+ (parents.detect{ |p| p.respond_to?(:table_name_prefix) } || self).table_name_prefix
+ end
+
# Defines the column name for use with single table inheritance
# -- can be set in subclasses like so: self.inheritance_column = "type_id"
def inheritance_column
@@ -1288,7 +1297,7 @@ module ActiveRecord #:nodoc:
# <tt>options</tt> argument is the same as in find.
#
# class Person < ActiveRecord::Base
- # default_scope :order => 'last_name, first_name'
+ # default_scope order('last_name, first_name')
# end
def default_scope(options = {})
self.default_scoping << construct_finder_arel(options)
@@ -2214,6 +2223,7 @@ module ActiveRecord #:nodoc:
extend QueryCache::ClassMethods
extend ActiveSupport::Benchmarkable
+ include ActiveModel::Conversion
include Validations
include Locking::Optimistic, Locking::Pessimistic
include AttributeMethods
@@ -2223,12 +2233,10 @@ module ActiveRecord #:nodoc:
include AttributeMethods::Dirty
include Callbacks, ActiveModel::Observing, Timestamp
include Associations, AssociationPreload, NamedScope
- include ActiveModel::Conversion
# AutosaveAssociation needs to be included before Transactions, because we want
# #save_with_autosave_associations to be wrapped inside a transaction.
include AutosaveAssociation, NestedAttributes
-
include Aggregations, Transactions, Reflection, Serialization
NilClass.add_whiner(self) if NilClass.respond_to?(:add_whiner)
@@ -2237,4 +2245,4 @@ end
# TODO: Remove this and make it work with LAZY flag
require 'active_record/connection_adapters/abstract_adapter'
-ActiveRecord.run_base_hooks(ActiveRecord::Base)
+ActiveSupport.run_load_hooks(:active_record, ActiveRecord::Base)
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/query_cache.rb b/activerecord/lib/active_record/connection_adapters/abstract/query_cache.rb
index 020acbbe5a..1e095110f2 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/query_cache.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/query_cache.rb
@@ -1,3 +1,5 @@
+require 'active_support/core_ext/object/duplicable'
+
module ActiveRecord
module ConnectionAdapters # :nodoc:
module QueryCache
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 64faaef4a0..046825d43f 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb
@@ -1,3 +1,4 @@
+require 'active_support/core_ext/object/blank'
require 'date'
require 'set'
require 'bigdecimal'
diff --git a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb
index 521bd810d0..55d9d20bb5 100644
--- a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb
@@ -1,5 +1,6 @@
require 'active_record/connection_adapters/abstract_adapter'
require 'active_support/core_ext/kernel/requires'
+require 'active_support/core_ext/object/blank'
require 'set'
module MysqlCompat #:nodoc:
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
index 31d5266da8..a6042e1382 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
@@ -1,5 +1,6 @@
require 'active_record/connection_adapters/abstract_adapter'
require 'active_support/core_ext/kernel/requires'
+require 'active_support/core_ext/object/blank'
begin
require_library_or_gem 'pg'
@@ -299,7 +300,7 @@ module ActiveRecord
# QUOTING ==================================================
# Escapes binary strings for bytea input to the database.
- def escape_bytea(value)
+ def escape_bytea(original_value)
if @connection.respond_to?(:escape_bytea)
self.class.instance_eval do
define_method(:escape_bytea) do |value|
@@ -323,13 +324,13 @@ module ActiveRecord
end
end
end
- escape_bytea(value)
+ escape_bytea(original_value)
end
# Unescapes bytea output from a database to the binary string it represents.
# NOTE: This is NOT an inverse of escape_bytea! This is only to be used
# on escaped binary output from database drive.
- def unescape_bytea(value)
+ def unescape_bytea(original_value)
# In each case, check if the value actually is escaped PostgreSQL bytea output
# or an unescaped Active Record attribute that was just written.
if PGconn.respond_to?(:unescape_bytea)
@@ -369,7 +370,7 @@ module ActiveRecord
end
end
end
- unescape_bytea(value)
+ unescape_bytea(original_value)
end
# Quotes PostgreSQL-specific data types for SQL input.
@@ -394,7 +395,7 @@ module ActiveRecord
end
# Quotes strings for use in SQL input in the postgres driver for better performance.
- def quote_string(s) #:nodoc:
+ def quote_string(original_value) #:nodoc:
if @connection.respond_to?(:escape)
self.class.instance_eval do
define_method(:quote_string) do |s|
@@ -414,7 +415,7 @@ module ActiveRecord
remove_method(:quote_string)
end
end
- quote_string(s)
+ quote_string(original_value)
end
# Checks the following cases:
diff --git a/activerecord/lib/active_record/fixtures.rb b/activerecord/lib/active_record/fixtures.rb
index 79f70f07cd..22f0e60083 100644
--- a/activerecord/lib/active_record/fixtures.rb
+++ b/activerecord/lib/active_record/fixtures.rb
@@ -4,6 +4,7 @@ require 'csv'
require 'zlib'
require 'active_support/dependencies'
require 'active_support/core_ext/logger'
+require 'active_support/core_ext/object/blank'
if RUBY_VERSION < '1.9'
module YAML #:nodoc:
diff --git a/activerecord/lib/active_record/named_scope.rb b/activerecord/lib/active_record/named_scope.rb
index 394e1587e1..9abf979cd0 100644
--- a/activerecord/lib/active_record/named_scope.rb
+++ b/activerecord/lib/active_record/named_scope.rb
@@ -1,6 +1,7 @@
require 'active_support/core_ext/array'
require 'active_support/core_ext/hash/except'
require 'active_support/core_ext/object/singleton_class'
+require 'active_support/core_ext/object/blank'
module ActiveRecord
module NamedScope
@@ -101,7 +102,8 @@ module ActiveRecord
name = name.to_sym
if !scopes[name] && respond_to?(name, true)
- raise ArgumentError, "Cannot define scope :#{name} because #{self.name}.#{name} method already exists."
+ logger.warn "Creating scope :#{name}. " \
+ "Overwriting existing method #{self.name}.#{name}."
end
scopes[name] = lambda do |parent_scope, *args|
@@ -165,7 +167,14 @@ module ActiveRecord
end
def ==(other)
- other.respond_to?(:to_ary) ? to_a == other.to_a : false
+ case other
+ when Scope
+ to_sql == other.to_sql
+ when Relation
+ other == self
+ when Array
+ to_a == other.to_a
+ end
end
private
diff --git a/activerecord/lib/active_record/nested_attributes.rb b/activerecord/lib/active_record/nested_attributes.rb
index 76ec7eb681..ee2d420194 100644
--- a/activerecord/lib/active_record/nested_attributes.rb
+++ b/activerecord/lib/active_record/nested_attributes.rb
@@ -1,5 +1,6 @@
require 'active_support/core_ext/hash/except'
require 'active_support/core_ext/object/try'
+require 'active_support/core_ext/object/blank'
module ActiveRecord
module NestedAttributes #:nodoc:
diff --git a/activerecord/lib/active_record/query_cache.rb b/activerecord/lib/active_record/query_cache.rb
index eb92bc2545..093c6c1e55 100644
--- a/activerecord/lib/active_record/query_cache.rb
+++ b/activerecord/lib/active_record/query_cache.rb
@@ -1,3 +1,5 @@
+require 'active_support/core_ext/object/blank'
+
module ActiveRecord
class QueryCache
module ClassMethods
diff --git a/activerecord/lib/active_record/railtie.rb b/activerecord/lib/active_record/railtie.rb
index de47461c73..04c4a9c153 100644
--- a/activerecord/lib/active_record/railtie.rb
+++ b/activerecord/lib/active_record/railtie.rb
@@ -23,18 +23,18 @@ module ActiveRecord
log_subscriber :active_record, ActiveRecord::Railties::LogSubscriber.new
initializer "active_record.initialize_timezone" do
- ActiveRecord.base_hook do
+ ActiveSupport.on_load(:active_record) do
self.time_zone_aware_attributes = true
self.default_timezone = :utc
end
end
initializer "active_record.logger" do
- ActiveRecord.base_hook { self.logger ||= ::Rails.logger }
+ ActiveSupport.on_load(:active_record) { self.logger ||= ::Rails.logger }
end
initializer "active_record.set_configs" do |app|
- ActiveRecord.base_hook do
+ ActiveSupport.on_load(:active_record) do
app.config.active_record.each do |k,v|
send "#{k}=", v
end
@@ -44,7 +44,7 @@ module ActiveRecord
# This sets the database configuration from Configuration#database_configuration
# and then establishes the connection.
initializer "active_record.initialize_database" do |app|
- ActiveRecord.base_hook do
+ ActiveSupport.on_load(:active_record) do
self.configurations = app.config.database_configuration
establish_connection
end
@@ -53,7 +53,7 @@ module ActiveRecord
# Expose database runtime to controller for logging.
initializer "active_record.log_runtime" do |app|
require "active_record/railties/controller_runtime"
- ActionController.base_hook do
+ ActiveSupport.on_load(:action_controller) do
include ActiveRecord::Railties::ControllerRuntime
end
end
@@ -71,9 +71,9 @@ module ActiveRecord
end
initializer "active_record.load_observers" do
- ActiveRecord.base_hook { instantiate_observers }
+ ActiveSupport.on_load(:active_record) { instantiate_observers }
- ActiveRecord.base_hook do
+ ActiveSupport.on_load(:active_record) do
ActionDispatch::Callbacks.to_prepare(:activerecord_instantiate_observers) do
ActiveRecord::Base.instantiate_observers
end
@@ -81,7 +81,7 @@ module ActiveRecord
end
initializer "active_record.set_dispatch_hooks", :before => :set_clear_dependencies_hook do |app|
- ActiveRecord.base_hook do
+ ActiveSupport.on_load(:active_record) do
unless app.config.cache_classes
ActionDispatch::Callbacks.after do
ActiveRecord::Base.reset_subclasses
diff --git a/activerecord/lib/active_record/relation.rb b/activerecord/lib/active_record/relation.rb
index a20c152eeb..8577ec58f7 100644
--- a/activerecord/lib/active_record/relation.rb
+++ b/activerecord/lib/active_record/relation.rb
@@ -1,3 +1,5 @@
+require 'active_support/core_ext/object/blank'
+
module ActiveRecord
class Relation
JoinOperation = Struct.new(:relation, :join_class, :on)
diff --git a/activerecord/lib/active_record/relation/batches.rb b/activerecord/lib/active_record/relation/batches.rb
index 4a260d4caa..1c61e7d450 100644
--- a/activerecord/lib/active_record/relation/batches.rb
+++ b/activerecord/lib/active_record/relation/batches.rb
@@ -1,3 +1,5 @@
+require 'active_support/core_ext/object/blank'
+
module ActiveRecord
module Batches # :nodoc:
# Yields each record that was found by the find +options+. The find is
@@ -48,6 +50,10 @@ module ActiveRecord
def find_in_batches(options = {})
relation = self
+ if orders.present? || taken.present?
+ ActiveRecord::Base.logger.warn("Scoped order and limit are ignored, it's forced to be batch order and batch size")
+ end
+
if (finder_options = options.except(:start, :batch_size)).present?
raise "You can't specify an order, it's forced to be #{batch_order}" if options[:order].present?
raise "You can't specify a limit, it's forced to be the batch_size" if options[:limit].present?
@@ -75,4 +81,4 @@ module ActiveRecord
"#{@klass.table_name}.#{@klass.primary_key} ASC"
end
end
-end \ No newline at end of file
+end
diff --git a/activerecord/lib/active_record/relation/calculations.rb b/activerecord/lib/active_record/relation/calculations.rb
index e77424a64b..a5ea6e7e3a 100644
--- a/activerecord/lib/active_record/relation/calculations.rb
+++ b/activerecord/lib/active_record/relation/calculations.rb
@@ -1,3 +1,5 @@
+require 'active_support/core_ext/object/blank'
+
module ActiveRecord
module Calculations
# Count operates using three different approaches.
diff --git a/activerecord/lib/active_record/relation/finder_methods.rb b/activerecord/lib/active_record/relation/finder_methods.rb
index c1cce679b6..37aaac0894 100644
--- a/activerecord/lib/active_record/relation/finder_methods.rb
+++ b/activerecord/lib/active_record/relation/finder_methods.rb
@@ -1,3 +1,5 @@
+require 'active_support/core_ext/object/blank'
+
module ActiveRecord
module FinderMethods
# Find operates with four different retrieval approaches:
diff --git a/activerecord/lib/active_record/relation/predicate_builder.rb b/activerecord/lib/active_record/relation/predicate_builder.rb
index 7e83eccbb5..711df16bf1 100644
--- a/activerecord/lib/active_record/relation/predicate_builder.rb
+++ b/activerecord/lib/active_record/relation/predicate_builder.rb
@@ -27,12 +27,7 @@ module ActiveRecord
values = value.to_a
attribute.in(values)
when Range
- # TODO : Arel should handle ranges with excluded end.
- if value.exclude_end?
- [attribute.gteq(value.begin), attribute.lt(value.end)]
- else
- attribute.in(value)
- end
+ attribute.in(value)
else
attribute.eq(value)
end
diff --git a/activerecord/lib/active_record/relation/query_methods.rb b/activerecord/lib/active_record/relation/query_methods.rb
index 0250e739b8..e224781016 100644
--- a/activerecord/lib/active_record/relation/query_methods.rb
+++ b/activerecord/lib/active_record/relation/query_methods.rb
@@ -1,3 +1,5 @@
+require 'active_support/core_ext/object/blank'
+
module ActiveRecord
module QueryMethods
extend ActiveSupport::Concern
diff --git a/activerecord/lib/active_record/relation/spawn_methods.rb b/activerecord/lib/active_record/relation/spawn_methods.rb
index 2841ff1239..a17de1bdbb 100644
--- a/activerecord/lib/active_record/relation/spawn_methods.rb
+++ b/activerecord/lib/active_record/relation/spawn_methods.rb
@@ -1,3 +1,5 @@
+require 'active_support/core_ext/object/blank'
+
module ActiveRecord
module SpawnMethods
def merge(r)
diff --git a/activerecord/lib/active_record/schema.rb b/activerecord/lib/active_record/schema.rb
index a996a0ebac..a833356d15 100644
--- a/activerecord/lib/active_record/schema.rb
+++ b/activerecord/lib/active_record/schema.rb
@@ -1,3 +1,5 @@
+require 'active_support/core_ext/object/blank'
+
module ActiveRecord
# Allows programmers to programmatically define a schema in a portable
# DSL. This means you can define tables, indexes, etc. without using SQL
diff --git a/activerecord/lib/active_record/validations/uniqueness.rb b/activerecord/lib/active_record/validations/uniqueness.rb
index e28808df98..4806fa0ecc 100644
--- a/activerecord/lib/active_record/validations/uniqueness.rb
+++ b/activerecord/lib/active_record/validations/uniqueness.rb
@@ -67,13 +67,11 @@ module ActiveRecord
if value.nil? || (options[:case_sensitive] || !column.text?)
sql = "#{sql_attribute} #{operator}"
- params = [value]
else
- sql = "LOWER(#{sql_attribute}) #{operator}"
- params = [value.mb_chars.downcase]
+ sql = "LOWER(#{sql_attribute}) = LOWER(?)"
end
- [sql, params]
+ [sql, [value]]
end
end
diff --git a/activerecord/test/cases/associations/belongs_to_associations_test.rb b/activerecord/test/cases/associations/belongs_to_associations_test.rb
index 41a23d7f61..62121b93cb 100644
--- a/activerecord/test/cases/associations/belongs_to_associations_test.rb
+++ b/activerecord/test/cases/associations/belongs_to_associations_test.rb
@@ -32,6 +32,17 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase
assert_equal companies(:first_firm).name, client.firm_with_primary_key.name
end
+ def test_belongs_to_with_primary_key_joins_on_correct_column
+ sql = Client.joins(:firm_with_primary_key).to_sql
+ if current_adapter?(:MysqlAdapter)
+ assert_no_match /`firm_with_primary_keys_companies`\.`id`/, sql
+ assert_match /`firm_with_primary_keys_companies`\.`name`/, sql
+ else
+ assert_no_match /"firm_with_primary_keys_companies"\."id"/, sql
+ assert_match /"firm_with_primary_keys_companies"\."name"/, sql
+ end
+ end
+
def test_proxy_assignment
account = Account.find(1)
assert_nothing_raised { account.firm = account.firm }
@@ -61,6 +72,13 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase
assert_equal apple.name, citibank.firm_name
end
+ def test_eager_loading_with_primary_key
+ apple = Firm.create("name" => "Apple")
+ citibank = Client.create("name" => "Citibank", :firm_name => "Apple")
+ citibank_result = Client.find(:first, :conditions => {:name => "Citibank"}, :include => :firm_with_primary_key)
+ assert_not_nil citibank_result.instance_variable_get("@firm_with_primary_key")
+ end
+
def test_no_unexpected_aliasing
first_firm = companies(:first_firm)
another_firm = companies(:another_firm)
@@ -439,9 +457,15 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase
assert_equal [author_address.id], AuthorAddress.destroyed_author_address_ids
end
- def test_invalid_belongs_to_dependent_option_raises_exception
+ def test_invalid_belongs_to_dependent_option_nullify_raises_exception
assert_raise ArgumentError do
Author.belongs_to :special_author_address, :dependent => :nullify
end
end
+
+ def test_invalid_belongs_to_dependent_option_restrict_raises_exception
+ assert_raise ArgumentError do
+ Author.belongs_to :special_author_address, :dependent => :restrict
+ end
+ end
end
diff --git a/activerecord/test/cases/associations/eager_test.rb b/activerecord/test/cases/associations/eager_test.rb
index 42a891bc3b..79e5ecf4ce 100644
--- a/activerecord/test/cases/associations/eager_test.rb
+++ b/activerecord/test/cases/associations/eager_test.rb
@@ -833,4 +833,10 @@ class EagerAssociationTest < ActiveRecord::TestCase
end
end
+ def test_preloading_empty_polymorphic_parent
+ t = Tagging.create!(:taggable_type => 'Post', :taggable_id => Post.maximum(:id) + 1, :tag => tags(:general))
+
+ assert_queries(2) { @tagging = Tagging.preload(:taggable).find(t.id) }
+ assert_no_queries { assert ! @tagging.taggable }
+ 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 54624e79ce..c1e539d573 100644
--- a/activerecord/test/cases/associations/has_many_associations_test.rb
+++ b/activerecord/test/cases/associations/has_many_associations_test.rb
@@ -836,6 +836,14 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
assert_equal num_accounts, Account.count
end
+ def test_restrict
+ firm = RestrictedFirm.new(:name => 'restrict')
+ firm.save!
+ child_firm = firm.companies.create(:name => 'child')
+ assert !firm.companies.empty?
+ assert_raise(ActiveRecord::DeleteRestrictionError) { firm.destroy }
+ end
+
def test_included_in_collection
assert companies(:first_firm).clients.include?(Client.find(2))
end
diff --git a/activerecord/test/cases/associations/has_one_associations_test.rb b/activerecord/test/cases/associations/has_one_associations_test.rb
index 7372f2da1b..8f5540950e 100644
--- a/activerecord/test/cases/associations/has_one_associations_test.rb
+++ b/activerecord/test/cases/associations/has_one_associations_test.rb
@@ -177,7 +177,15 @@ class HasOneAssociationsTest < ActiveRecord::TestCase
assert_nothing_raised { firm.destroy }
end
- def test_succesful_build_association
+ def test_dependence_with_restrict
+ firm = RestrictedFirm.new(:name => 'restrict')
+ firm.save!
+ account = firm.create_account(:credit_limit => 10)
+ assert !firm.account.nil?
+ assert_raise(ActiveRecord::DeleteRestrictionError) { firm.destroy }
+ end
+
+ def test_successful_build_association
firm = Firm.new("name" => "GlobalMegaCorp")
firm.save
diff --git a/activerecord/test/cases/batches_test.rb b/activerecord/test/cases/batches_test.rb
index e417d8a803..83deabb5b7 100644
--- a/activerecord/test/cases/batches_test.rb
+++ b/activerecord/test/cases/batches_test.rb
@@ -8,7 +8,7 @@ class EachTest < ActiveRecord::TestCase
@posts = Post.order("id asc")
@total = Post.count
end
-
+
def test_each_should_excecute_one_query_per_batch
assert_queries(Post.count + 1) do
Post.find_each(:batch_size => 1) do |post|
@@ -28,7 +28,17 @@ class EachTest < ActiveRecord::TestCase
Post.find_each(:limit => 1) { |post| post }
end
end
-
+
+ def test_warn_if_limit_scope_is_set
+ ActiveRecord::Base.logger.expects(:warn)
+ Post.limit(1).find_each { |post| post }
+ end
+
+ def test_warn_if_order_scope_is_set
+ ActiveRecord::Base.logger.expects(:warn)
+ Post.order("title").find_each { |post| post }
+ end
+
def test_find_in_batches_should_return_batches
assert_queries(Post.count + 1) do
Post.find_in_batches(:batch_size => 1) do |batch|
@@ -58,4 +68,4 @@ class EachTest < ActiveRecord::TestCase
Post.find_in_batches(:batch_size => post_count + 1) {|batch| assert_kind_of Array, batch }
end
end
-end \ No newline at end of file
+end
diff --git a/activerecord/test/cases/modules_test.rb b/activerecord/test/cases/modules_test.rb
index d781a229f4..7209966bf8 100644
--- a/activerecord/test/cases/modules_test.rb
+++ b/activerecord/test/cases/modules_test.rb
@@ -82,4 +82,32 @@ class ModulesTest < ActiveRecord::TestCase
end
end
end
+
+ def test_module_table_name_prefix
+ assert_equal 'prefixed_companies', MyApplication::Business::Prefixed::Company.table_name, 'inferred table_name for ActiveRecord model in module with table_name_prefix'
+ assert_equal 'prefixed_companies', MyApplication::Business::Prefixed::Nested::Company.table_name, 'table_name for ActiveRecord model in nested module with a parent table_name_prefix'
+ assert_equal 'companies', MyApplication::Business::Prefixed::Firm.table_name, 'explicit table_name for ActiveRecord model in module with table_name_prefix should not be prefixed'
+ end
+
+ def test_module_table_name_prefix_with_global_prefix
+ classes = [ MyApplication::Business::Company,
+ MyApplication::Business::Firm,
+ MyApplication::Business::Client,
+ MyApplication::Business::Client::Contact,
+ MyApplication::Business::Developer,
+ MyApplication::Business::Project,
+ MyApplication::Business::Prefixed::Company,
+ MyApplication::Business::Prefixed::Nested::Company,
+ MyApplication::Billing::Account ]
+
+ ActiveRecord::Base.table_name_prefix = 'global_'
+ classes.each(&:reset_table_name)
+ assert_equal 'global_companies', MyApplication::Business::Company.table_name, 'inferred table_name for ActiveRecord model in module without table_name_prefix'
+ assert_equal 'prefixed_companies', MyApplication::Business::Prefixed::Company.table_name, 'inferred table_name for ActiveRecord model in module with table_name_prefix'
+ assert_equal 'prefixed_companies', MyApplication::Business::Prefixed::Nested::Company.table_name, 'table_name for ActiveRecord model in nested module with a parent table_name_prefix'
+ assert_equal 'companies', MyApplication::Business::Prefixed::Firm.table_name, 'explicit table_name for ActiveRecord model in module with table_name_prefix should not be prefixed'
+ ensure
+ ActiveRecord::Base.table_name_prefix = ''
+ classes.each(&:reset_table_name)
+ end
end
diff --git a/activerecord/test/cases/named_scope_test.rb b/activerecord/test/cases/named_scope_test.rb
index 6c2b4fa3a7..2396ca10b0 100644
--- a/activerecord/test/cases/named_scope_test.rb
+++ b/activerecord/test/cases/named_scope_test.rb
@@ -371,8 +371,21 @@ class NamedScopeTest < ActiveRecord::TestCase
end
def test_named_scopes_with_reserved_names
- [:where, :with_scope].each do |protected_method|
- assert_raises(ArgumentError) { Topic.scope protected_method }
+ class << Topic
+ def public_method; end
+ public :public_method
+
+ def protected_method; end
+ protected :protected_method
+
+ def private_method; end
+ private :private_method
+ end
+
+ [:public_method, :protected_method, :private_method].each do |reserved_method|
+ assert Topic.respond_to?(reserved_method, true)
+ ActiveRecord::Base.logger.expects(:warn)
+ Topic.scope(reserved_method)
end
end
@@ -394,6 +407,12 @@ class NamedScopeTest < ActiveRecord::TestCase
assert_equal topics(:second), approved[0]
assert approved.loaded?
end
+
+ def test_nested_named_scopes_queries_size
+ assert_queries(1) do
+ Topic.approved.by_lifo.replied.written_before(Time.now).all
+ end
+ end
end
class DynamicScopeMatchTest < ActiveRecord::TestCase
diff --git a/activerecord/test/cases/pk_test.rb b/activerecord/test/cases/pk_test.rb
index 5bba1d5625..33ad5992de 100644
--- a/activerecord/test/cases/pk_test.rb
+++ b/activerecord/test/cases/pk_test.rb
@@ -23,6 +23,12 @@ class PrimaryKeysTest < ActiveRecord::TestCase
assert_equal keyboard.to_key, [keyboard.id]
end
+ def test_to_key_with_primary_key_after_destroy
+ topic = Topic.find(1)
+ topic.destroy
+ assert_equal topic.to_key, [1]
+ end
+
def test_integer_key
topic = Topic.find(1)
assert_equal(topics(:first).author_name, topic.author_name)
diff --git a/activerecord/test/models/company.rb b/activerecord/test/models/company.rb
index f31d5f87e5..be6dd71e3b 100644
--- a/activerecord/test/models/company.rb
+++ b/activerecord/test/models/company.rb
@@ -95,6 +95,11 @@ class DependentFirm < Company
has_many :companies, :foreign_key => 'client_of', :dependent => :nullify
end
+class RestrictedFirm < Company
+ has_one :account, :foreign_key => "firm_id", :dependent => :restrict, :order => "id"
+ has_many :companies, :foreign_key => 'client_of', :order => "id", :dependent => :restrict
+end
+
class Client < Company
belongs_to :firm, :foreign_key => "client_of"
belongs_to :firm_with_basic_id, :class_name => "Firm", :foreign_key => "firm_id"
diff --git a/activerecord/test/models/company_in_module.rb b/activerecord/test/models/company_in_module.rb
index cdda7a44d4..83d71b6909 100644
--- a/activerecord/test/models/company_in_module.rb
+++ b/activerecord/test/models/company_in_module.rb
@@ -32,6 +32,23 @@ module MyApplication
has_and_belongs_to_many :developers
end
+ module Prefixed
+ def self.table_name_prefix
+ 'prefixed_'
+ end
+
+ class Company < ActiveRecord::Base
+ end
+
+ class Firm < Company
+ self.table_name = 'companies'
+ end
+
+ module Nested
+ class Company < ActiveRecord::Base
+ end
+ end
+ end
end
module Billing