aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord/lib/active_record
diff options
context:
space:
mode:
Diffstat (limited to 'activerecord/lib/active_record')
-rw-r--r--activerecord/lib/active_record/association_preload.rb4
-rwxr-xr-xactiverecord/lib/active_record/associations.rb37
-rw-r--r--activerecord/lib/active_record/associations/association_proxy.rb1
-rw-r--r--activerecord/lib/active_record/associations/has_one_through_association.rb7
-rwxr-xr-xactiverecord/lib/active_record/base.rb54
-rw-r--r--activerecord/lib/active_record/calculations.rb2
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb22
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb8
-rwxr-xr-xactiverecord/lib/active_record/connection_adapters/abstract_adapter.rb6
-rw-r--r--activerecord/lib/active_record/fixtures.rb289
-rw-r--r--activerecord/lib/active_record/locale/en.yml (renamed from activerecord/lib/active_record/locale/en-US.yml)2
-rw-r--r--activerecord/lib/active_record/serialization.rb4
-rw-r--r--activerecord/lib/active_record/test_case.rb16
-rw-r--r--activerecord/lib/active_record/version.rb2
14 files changed, 251 insertions, 203 deletions
diff --git a/activerecord/lib/active_record/association_preload.rb b/activerecord/lib/active_record/association_preload.rb
index 6e194ab9b4..99c3ce5e62 100644
--- a/activerecord/lib/active_record/association_preload.rb
+++ b/activerecord/lib/active_record/association_preload.rb
@@ -185,7 +185,7 @@ module ActiveRecord
associated_records = reflection.klass.find(:all, :conditions => [conditions, ids],
:include => options[:include],
- :joins => "INNER JOIN #{connection.quote_table_name options[:join_table]} as t0 ON #{reflection.klass.quoted_table_name}.#{reflection.klass.primary_key} = t0.#{reflection.association_foreign_key}",
+ :joins => "INNER JOIN #{connection.quote_table_name options[:join_table]} t0 ON #{reflection.klass.quoted_table_name}.#{reflection.klass.primary_key} = t0.#{reflection.association_foreign_key}",
:select => "#{options[:select] || table_name+'.*'}, t0.#{reflection.primary_key_name} as the_parent_record_id",
:order => options[:order])
@@ -312,7 +312,7 @@ module ActiveRecord
table_name = klass.quoted_table_name
primary_key = klass.primary_key
column_type = klass.columns.detect{|c| c.name == primary_key}.type
- ids = id_map.keys.uniq.map do |id|
+ ids = id_map.keys.map do |id|
if column_type == :integer
id.to_i
elsif column_type == :float
diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb
index c7cb6eb966..3fbbea43ed 100755
--- a/activerecord/lib/active_record/associations.rb
+++ b/activerecord/lib/active_record/associations.rb
@@ -1,13 +1,3 @@
-require 'active_record/associations/association_proxy'
-require 'active_record/associations/association_collection'
-require 'active_record/associations/belongs_to_association'
-require 'active_record/associations/belongs_to_polymorphic_association'
-require 'active_record/associations/has_one_association'
-require 'active_record/associations/has_many_association'
-require 'active_record/associations/has_many_through_association'
-require 'active_record/associations/has_and_belongs_to_many_association'
-require 'active_record/associations/has_one_through_association'
-
module ActiveRecord
class HasManyThroughAssociationNotFoundError < ActiveRecordError #:nodoc:
def initialize(owner_class_name, reflection)
@@ -75,6 +65,18 @@ module ActiveRecord
# See ActiveRecord::Associations::ClassMethods for documentation.
module Associations # :nodoc:
+ # These classes will be loaded when associatoins are created.
+ # So there is no need to eager load them.
+ autoload :AssociationCollection, 'active_record/associations/association_collection'
+ autoload :AssociationProxy, 'active_record/associations/association_proxy'
+ autoload :BelongsToAssociation, 'active_record/associations/belongs_to_association'
+ autoload :BelongsToPolymorphicAssociation, 'active_record/associations/belongs_to_polymorphic_association'
+ autoload :HasAndBelongsToManyAssociation, 'active_record/associations/has_and_belongs_to_many_association'
+ autoload :HasManyAssociation, 'active_record/associations/has_many_association'
+ autoload :HasManyThroughAssociation, 'active_record/associations/has_many_through_association'
+ autoload :HasOneAssociation, 'active_record/associations/has_one_association'
+ autoload :HasOneThroughAssociation, 'active_record/associations/has_one_through_association'
+
def self.included(base)
base.extend(ClassMethods)
end
@@ -722,6 +724,8 @@ module ActiveRecord
# Specify second-order associations that should be eager loaded when the collection is loaded.
# [:group]
# An attribute name by which the result should be grouped. Uses the <tt>GROUP BY</tt> SQL-clause.
+ # [:having]
+ # Combined with +:group+ this can be used to filter the records that a <tt>GROUP BY</tt> returns. Uses the <tt>HAVING</tt> SQL-clause.
# [:limit]
# An integer determining the limit on the number of rows that should be returned.
# [:offset]
@@ -1179,6 +1183,8 @@ module ActiveRecord
# Specify second-order associations that should be eager loaded when the collection is loaded.
# [:group]
# An attribute name by which the result should be grouped. Uses the <tt>GROUP BY</tt> SQL-clause.
+ # [:having]
+ # Combined with +:group+ this can be used to filter the records that a <tt>GROUP BY</tt> returns. Uses the <tt>HAVING</tt> SQL-clause.
# [:limit]
# An integer determining the limit on the number of rows that should be returned.
# [:offset]
@@ -1551,7 +1557,7 @@ module ActiveRecord
@@valid_keys_for_has_many_association = [
:class_name, :table_name, :foreign_key, :primary_key,
:dependent,
- :select, :conditions, :include, :order, :group, :limit, :offset,
+ :select, :conditions, :include, :order, :group, :having, :limit, :offset,
:as, :through, :source, :source_type,
:uniq,
:finder_sql, :counter_sql,
@@ -1607,9 +1613,9 @@ module ActiveRecord
mattr_accessor :valid_keys_for_has_and_belongs_to_many_association
@@valid_keys_for_has_and_belongs_to_many_association = [
:class_name, :table_name, :join_table, :foreign_key, :association_foreign_key,
- :select, :conditions, :include, :order, :group, :limit, :offset,
+ :select, :conditions, :include, :order, :group, :having, :limit, :offset,
:uniq,
- :finder_sql, :delete_sql, :insert_sql,
+ :finder_sql, :counter_sql, :delete_sql, :insert_sql,
:before_add, :after_add, :before_remove, :after_remove,
:extend, :readonly,
:validate
@@ -1656,7 +1662,7 @@ module ActiveRecord
add_conditions!(sql, options[:conditions], scope)
add_limited_ids_condition!(sql, options, join_dependency) if !using_limitable_reflections?(join_dependency.reflections) && ((scope && scope[:limit]) || options[:limit])
- add_group!(sql, options[:group], scope)
+ add_group!(sql, options[:group], options[:having], scope)
add_order!(sql, options[:order], scope)
add_limit!(sql, options, scope) if using_limitable_reflections?(join_dependency.reflections)
add_lock!(sql, options, scope)
@@ -1712,7 +1718,7 @@ module ActiveRecord
end
add_conditions!(sql, options[:conditions], scope)
- add_group!(sql, options[:group], scope)
+ add_group!(sql, options[:group], options[:having], scope)
if order && is_distinct
connection.add_order_by_for_association_limiting!(sql, :order => order)
@@ -1731,6 +1737,7 @@ module ActiveRecord
case cond
when nil then all
when Array then all << cond.first
+ when Hash then all << cond.keys
else all << cond
end
end
diff --git a/activerecord/lib/active_record/associations/association_proxy.rb b/activerecord/lib/active_record/associations/association_proxy.rb
index d1a79df6e6..75ec4fbb2e 100644
--- a/activerecord/lib/active_record/associations/association_proxy.rb
+++ b/activerecord/lib/active_record/associations/association_proxy.rb
@@ -188,6 +188,7 @@ module ActiveRecord
def merge_options_from_reflection!(options)
options.reverse_merge!(
:group => @reflection.options[:group],
+ :having => @reflection.options[:having],
:limit => @reflection.options[:limit],
:offset => @reflection.options[:offset],
:joins => @reflection.options[:joins],
diff --git a/activerecord/lib/active_record/associations/has_one_through_association.rb b/activerecord/lib/active_record/associations/has_one_through_association.rb
index b78bd5d931..8073ebaf9f 100644
--- a/activerecord/lib/active_record/associations/has_one_through_association.rb
+++ b/activerecord/lib/active_record/associations/has_one_through_association.rb
@@ -8,11 +8,10 @@ module ActiveRecord
current_object = @owner.send(@reflection.through_reflection.name)
if current_object
- klass.destroy(current_object)
- @owner.clear_association_cache
+ current_object.update_attributes(construct_join_attributes(new_value))
+ else
+ @owner.send(@reflection.through_reflection.name, klass.send(:create, construct_join_attributes(new_value)))
end
-
- @owner.send(@reflection.through_reflection.name, klass.send(:create, construct_join_attributes(new_value)))
end
private
diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb
index a36a137f0d..8f8ed241d5 100755
--- a/activerecord/lib/active_record/base.rb
+++ b/activerecord/lib/active_record/base.rb
@@ -495,6 +495,10 @@ module ActiveRecord #:nodoc:
superclass_delegating_accessor :store_full_sti_class
self.store_full_sti_class = false
+ # Stores the default scope for the class
+ class_inheritable_accessor :default_scoping, :instance_writer => false
+ self.default_scoping = []
+
class << self # Class methods
# Find operates with four different retrieval approaches:
#
@@ -517,6 +521,7 @@ module ActiveRecord #:nodoc:
# * <tt>:conditions</tt> - An SQL fragment like "administrator = 1", <tt>[ "user_name = ?", username ]</tt>, or <tt>["user_name = :user_name", { :user_name => user_name }]</tt>. See conditions in the intro.
# * <tt>:order</tt> - An SQL fragment like "created_at DESC, name".
# * <tt>:group</tt> - An attribute name by which the result should be grouped. Uses the <tt>GROUP BY</tt> SQL-clause.
+ # * <tt>:having</tt> - Combined with +:group+ this can be used to filter the records that a <tt>GROUP BY</tt> returns. Uses the <tt>HAVING</tt> SQL-clause.
# * <tt>:limit</tt> - An integer determining the limit on the number of rows that should be returned.
# * <tt>:offset</tt> - An integer determining the offset from where the rows should be fetched. So at 5, it would skip rows 0 through 4.
# * <tt>:joins</tt> - Either an SQL fragment for additional joins like "LEFT JOIN comments ON comments.post_id = id" (rarely needed)
@@ -1612,15 +1617,23 @@ module ActiveRecord #:nodoc:
end
end
+ def default_select(qualified)
+ if qualified
+ quoted_table_name + '.*'
+ else
+ '*'
+ end
+ end
+
def construct_finder_sql(options)
scope = scope(:find)
- sql = "SELECT #{options[:select] || (scope && scope[:select]) || ((options[:joins] || (scope && scope[:joins])) && quoted_table_name + '.*') || '*'} "
+ sql = "SELECT #{options[:select] || (scope && scope[:select]) || default_select(options[:joins] || (scope && scope[:joins]))} "
sql << "FROM #{(scope && scope[:from]) || options[:from] || quoted_table_name} "
add_joins!(sql, options[:joins], scope)
add_conditions!(sql, options[:conditions], scope)
- add_group!(sql, options[:group], scope)
+ add_group!(sql, options[:group], options[:having], scope)
add_order!(sql, options[:order], scope)
add_limit!(sql, options, scope)
add_lock!(sql, options, scope)
@@ -1676,13 +1689,15 @@ module ActiveRecord #:nodoc:
end
end
- def add_group!(sql, group, scope = :auto)
+ def add_group!(sql, group, having, scope = :auto)
if group
sql << " GROUP BY #{group}"
+ sql << " HAVING #{having}" if having
else
scope = scope(:find) if :auto == scope
if scope && (scoped_group = scope[:group])
sql << " GROUP BY #{scoped_group}"
+ sql << " HAVING #{scoped_having}" if (scoped_having = scope[:having])
end
end
end
@@ -2008,6 +2023,16 @@ module ActiveRecord #:nodoc:
@@subclasses[self] + extra = @@subclasses[self].inject([]) {|list, subclass| list + subclass.subclasses }
end
+ # Sets the default options for the model. The format of the
+ # <tt>method_scoping</tt> argument is the same as in with_scope.
+ #
+ # class Person < ActiveRecord::Base
+ # default_scope :find => { :order => 'last_name, first_name' }
+ # end
+ def default_scope(options = {})
+ self.default_scoping << { :find => options, :create => (options.is_a?(Hash) && options.has_key?(:conditions)) ? options[:conditions] : {} }
+ end
+
# Test whether the given method and optional key are scoped.
def scoped?(method, key = nil) #:nodoc:
if current_scoped_methods && (scope = current_scoped_methods[method])
@@ -2023,8 +2048,7 @@ module ActiveRecord #:nodoc:
end
def scoped_methods #:nodoc:
- scoped_methods = (Thread.current[:scoped_methods] ||= {})
- scoped_methods[self] ||= []
+ Thread.current[:"#{self}_scoped_methods"] ||= self.default_scoping.dup
end
def current_scoped_methods #:nodoc:
@@ -2238,7 +2262,7 @@ module ActiveRecord #:nodoc:
end
VALID_FIND_OPTIONS = [ :conditions, :include, :joins, :limit, :offset,
- :order, :select, :readonly, :group, :from, :lock ]
+ :order, :select, :readonly, :group, :having, :from, :lock ]
def validate_find_options(options) #:nodoc:
options.assert_valid_keys(VALID_FIND_OPTIONS)
@@ -2301,7 +2325,7 @@ module ActiveRecord #:nodoc:
# construct an URI with the user object's 'id' in it:
#
# user = User.find_by_name('Phusion')
- # user_path(path) # => "/users/1"
+ # user_path(user) # => "/users/1"
#
# You can override +to_param+ in your model to make +users_path+ construct
# an URI using the user's name instead of the user's id:
@@ -2313,7 +2337,7 @@ module ActiveRecord #:nodoc:
# end
#
# user = User.find_by_name('Phusion')
- # user_path(path) # => "/users/Phusion"
+ # user_path(user) # => "/users/Phusion"
def to_param
# We can't use alias_method here, because method 'id' optimizes itself on the fly.
(id = self.id) ? id.to_s : nil # Be sure to stringify the id for routes
@@ -2957,4 +2981,18 @@ module ActiveRecord #:nodoc:
value
end
end
+
+ Base.class_eval do
+ extend QueryCache
+ include Validations
+ include Locking::Optimistic, Locking::Pessimistic
+ include AttributeMethods
+ include Dirty
+ include Callbacks, Observing, Timestamp
+ include Associations, AssociationPreload, NamedScope
+ include Aggregations, Transactions, Reflection, Calculations, Serialization
+ end
end
+
+# TODO: Remove this and make it work with LAZY flag
+require 'active_record/connection_adapters/abstract_adapter'
diff --git a/activerecord/lib/active_record/calculations.rb b/activerecord/lib/active_record/calculations.rb
index 5e33cf1bd4..65512d534a 100644
--- a/activerecord/lib/active_record/calculations.rb
+++ b/activerecord/lib/active_record/calculations.rb
@@ -286,7 +286,7 @@ module ActiveRecord
case operation
when 'count' then value.to_i
when 'sum' then type_cast_using_column(value || '0', column)
- when 'avg' then value && value.to_d
+ when 'avg' then value && (value.is_a?(Fixnum) ? value.to_f : value).to_d
else type_cast_using_column(value, column)
end
end
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb b/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb
index 432c341e6c..901b17124c 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb
@@ -65,15 +65,23 @@ module ActiveRecord
# The default ConnectionPool maximum size is 5.
def initialize(spec)
@spec = spec
+
# The cache of reserved connections mapped to threads
@reserved_connections = {}
+
# The mutex used to synchronize pool access
@connection_mutex = Monitor.new
@queue = @connection_mutex.new_cond
- # default 5 second timeout
- @timeout = spec.config[:wait_timeout] || 5
+
+ # default 5 second timeout unless on ruby 1.9
+ @timeout =
+ if RUBY_VERSION < '1.9'
+ spec.config[:wait_timeout] || 5
+ end
+
# default max pool size to 5
@size = (spec.config[:pool] && spec.config[:pool].to_i) || 5
+
@connections = []
@checked_out = []
end
@@ -187,7 +195,7 @@ module ActiveRecord
# try looting dead threads
clear_stale_cached_connections!
if @size == @checked_out.size
- raise ConnectionTimeoutError, "could not obtain a database connection within #{@timeout} seconds. The pool size is currently #{@size}, perhaps you need to increase it?"
+ raise ConnectionTimeoutError, "could not obtain a database connection#{" within #{@timeout} seconds" if @timeout}. The max pool size is currently #{@size}; consider increasing it."
end
end
end
@@ -292,10 +300,7 @@ module ActiveRecord
# and also returns connections to the pool cached by threads that are no
# longer alive.
def clear_active_connections!
- @connection_pools.each_value do |pool|
- pool.release_connection
- pool.clear_stale_cached_connections!
- end
+ @connection_pools.each_value {|pool| pool.release_connection }
end
# Clears the cache which maps classes
@@ -324,7 +329,8 @@ module ActiveRecord
# Returns true if a connection that's accessible to this class has
# already been opened.
def connected?(klass)
- retrieve_connection_pool(klass).connected?
+ conn = retrieve_connection_pool(klass)
+ conn ? conn.connected? : false
end
# Remove the connection for this class. This will close the active
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb b/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb
index a9a63e5a9f..cecbc6b3ac 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb
@@ -31,13 +31,13 @@ module ActiveRecord
# Returns an array of arrays containing the field values.
# Order is the same as that returned by +columns+.
def select_rows(sql, name = nil)
- raise NotImplementedError, "select_rows is an abstract method"
end
+ undef_method :select_rows
# Executes the SQL statement in the context of this connection.
- def execute(sql, name = nil)
- raise NotImplementedError, "execute is an abstract method"
+ def execute(sql, name = nil, skip_logging = false)
end
+ undef_method :execute
# Returns the last auto-generated ID from the affected table.
def insert(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil)
@@ -246,8 +246,8 @@ module ActiveRecord
# Returns an array of record hashes with the column names as keys and
# column values as values.
def select(sql, name = nil)
- raise NotImplementedError, "select is an abstract method"
end
+ undef_method :select
# Returns the last auto-generated ID from the affected table.
def insert_sql(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil)
diff --git a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb
index 81260eeecc..b26185580c 100755
--- a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb
@@ -3,6 +3,7 @@ require 'date'
require 'bigdecimal'
require 'bigdecimal/util'
+# TODO: Autoload these files
require 'active_record/connection_adapters/abstract/schema_definitions'
require 'active_record/connection_adapters/abstract/schema_statements'
require 'active_record/connection_adapters/abstract/database_statements'
@@ -31,7 +32,7 @@ module ActiveRecord
include QueryCache
include ActiveSupport::Callbacks
define_callbacks :checkout, :checkin
- checkout :reset!
+
@@row_even = true
def initialize(connection, logger = nil) #:nodoc:
@@ -131,9 +132,8 @@ module ActiveRecord
end
# Returns true if its safe to reload the connection between requests for development mode.
- # This is not the case for Ruby/MySQL and it's not necessary for any adapters except SQLite.
def requires_reloading?
- false
+ true
end
# Checks whether the connection to the database is still active (i.e. not stale).
diff --git a/activerecord/lib/active_record/fixtures.rb b/activerecord/lib/active_record/fixtures.rb
index 3d8b0e40a9..039d5a4e8e 100644
--- a/activerecord/lib/active_record/fixtures.rb
+++ b/activerecord/lib/active_record/fixtures.rb
@@ -1,6 +1,7 @@
require 'erb'
require 'yaml'
require 'csv'
+require 'active_support/dependencies'
require 'active_support/test_case'
if RUBY_VERSION < '1.9'
@@ -813,188 +814,192 @@ class Fixture #:nodoc:
end
end
-module Test #:nodoc:
- module Unit #:nodoc:
- class TestCase #:nodoc:
- setup :setup_fixtures
- teardown :teardown_fixtures
-
- superclass_delegating_accessor :fixture_path
- superclass_delegating_accessor :fixture_table_names
- superclass_delegating_accessor :fixture_class_names
- superclass_delegating_accessor :use_transactional_fixtures
- superclass_delegating_accessor :use_instantiated_fixtures # true, false, or :no_instances
- superclass_delegating_accessor :pre_loaded_fixtures
-
- self.fixture_table_names = []
- self.use_transactional_fixtures = false
- self.use_instantiated_fixtures = true
- self.pre_loaded_fixtures = false
-
- @@already_loaded_fixtures = {}
- self.fixture_class_names = {}
-
- class << self
- def set_fixture_class(class_names = {})
- self.fixture_class_names = self.fixture_class_names.merge(class_names)
- end
+module ActiveRecord
+ module TestFixtures
+ def self.included(base)
+ base.class_eval do
+ setup :setup_fixtures
+ teardown :teardown_fixtures
+
+ superclass_delegating_accessor :fixture_path
+ superclass_delegating_accessor :fixture_table_names
+ superclass_delegating_accessor :fixture_class_names
+ superclass_delegating_accessor :use_transactional_fixtures
+ superclass_delegating_accessor :use_instantiated_fixtures # true, false, or :no_instances
+ superclass_delegating_accessor :pre_loaded_fixtures
+
+ self.fixture_table_names = []
+ self.use_transactional_fixtures = false
+ self.use_instantiated_fixtures = true
+ self.pre_loaded_fixtures = false
+
+ self.fixture_class_names = {}
+ end
- def fixtures(*table_names)
- if table_names.first == :all
- table_names = Dir["#{fixture_path}/*.yml"] + Dir["#{fixture_path}/*.csv"]
- table_names.map! { |f| File.basename(f).split('.')[0..-2].join('.') }
- else
- table_names = table_names.flatten.map { |n| n.to_s }
- end
+ base.extend ClassMethods
+ end
+
+ module ClassMethods
+ def set_fixture_class(class_names = {})
+ self.fixture_class_names = self.fixture_class_names.merge(class_names)
+ end
- self.fixture_table_names |= table_names
- require_fixture_classes(table_names)
- setup_fixture_accessors(table_names)
+ def fixtures(*table_names)
+ if table_names.first == :all
+ table_names = Dir["#{fixture_path}/*.yml"] + Dir["#{fixture_path}/*.csv"]
+ table_names.map! { |f| File.basename(f).split('.')[0..-2].join('.') }
+ else
+ table_names = table_names.flatten.map { |n| n.to_s }
end
- def try_to_load_dependency(file_name)
- require_dependency file_name
- rescue LoadError => e
- # Let's hope the developer has included it himself
+ self.fixture_table_names |= table_names
+ require_fixture_classes(table_names)
+ setup_fixture_accessors(table_names)
+ end
+
+ def try_to_load_dependency(file_name)
+ require_dependency file_name
+ rescue LoadError => e
+ # Let's hope the developer has included it himself
- # Let's warn in case this is a subdependency, otherwise
- # subdependency error messages are totally cryptic
- if ActiveRecord::Base.logger
- ActiveRecord::Base.logger.warn("Unable to load #{file_name}, underlying cause #{e.message} \n\n #{e.backtrace.join("\n")}")
- end
+ # Let's warn in case this is a subdependency, otherwise
+ # subdependency error messages are totally cryptic
+ if ActiveRecord::Base.logger
+ ActiveRecord::Base.logger.warn("Unable to load #{file_name}, underlying cause #{e.message} \n\n #{e.backtrace.join("\n")}")
end
+ end
- def require_fixture_classes(table_names = nil)
- (table_names || fixture_table_names).each do |table_name|
- file_name = table_name.to_s
- file_name = file_name.singularize if ActiveRecord::Base.pluralize_table_names
- try_to_load_dependency(file_name)
- end
+ def require_fixture_classes(table_names = nil)
+ (table_names || fixture_table_names).each do |table_name|
+ file_name = table_name.to_s
+ file_name = file_name.singularize if ActiveRecord::Base.pluralize_table_names
+ try_to_load_dependency(file_name)
end
+ end
- def setup_fixture_accessors(table_names = nil)
- table_names = [table_names] if table_names && !table_names.respond_to?(:each)
- (table_names || fixture_table_names).each do |table_name|
- table_name = table_name.to_s.tr('.', '_')
+ def setup_fixture_accessors(table_names = nil)
+ table_names = [table_names] if table_names && !table_names.respond_to?(:each)
+ (table_names || fixture_table_names).each do |table_name|
+ table_name = table_name.to_s.tr('.', '_')
- define_method(table_name) do |*fixtures|
- force_reload = fixtures.pop if fixtures.last == true || fixtures.last == :reload
+ define_method(table_name) do |*fixtures|
+ force_reload = fixtures.pop if fixtures.last == true || fixtures.last == :reload
- @fixture_cache[table_name] ||= {}
+ @fixture_cache[table_name] ||= {}
- instances = fixtures.map do |fixture|
- @fixture_cache[table_name].delete(fixture) if force_reload
+ instances = fixtures.map do |fixture|
+ @fixture_cache[table_name].delete(fixture) if force_reload
- if @loaded_fixtures[table_name][fixture.to_s]
- @fixture_cache[table_name][fixture] ||= @loaded_fixtures[table_name][fixture.to_s].find
- else
- raise StandardError, "No fixture with name '#{fixture}' found for table '#{table_name}'"
- end
+ if @loaded_fixtures[table_name][fixture.to_s]
+ @fixture_cache[table_name][fixture] ||= @loaded_fixtures[table_name][fixture.to_s].find
+ else
+ raise StandardError, "No fixture with name '#{fixture}' found for table '#{table_name}'"
end
-
- instances.size == 1 ? instances.first : instances
end
- end
- end
- def uses_transaction(*methods)
- @uses_transaction = [] unless defined?(@uses_transaction)
- @uses_transaction.concat methods.map(&:to_s)
+ instances.size == 1 ? instances.first : instances
+ end
end
+ end
- def uses_transaction?(method)
- @uses_transaction = [] unless defined?(@uses_transaction)
- @uses_transaction.include?(method.to_s)
- end
+ def uses_transaction(*methods)
+ @uses_transaction = [] unless defined?(@uses_transaction)
+ @uses_transaction.concat methods.map(&:to_s)
end
- def use_transactional_fixtures?
- use_transactional_fixtures &&
- !self.class.uses_transaction?(method_name)
+ def uses_transaction?(method)
+ @uses_transaction = [] unless defined?(@uses_transaction)
+ @uses_transaction.include?(method.to_s)
end
+ end
- def setup_fixtures
- return unless defined?(ActiveRecord) && !ActiveRecord::Base.configurations.blank?
+ def run_in_transaction?
+ use_transactional_fixtures &&
+ !self.class.uses_transaction?(method_name)
+ end
- if pre_loaded_fixtures && !use_transactional_fixtures
- raise RuntimeError, 'pre_loaded_fixtures requires use_transactional_fixtures'
- end
+ def setup_fixtures
+ return unless defined?(ActiveRecord) && !ActiveRecord::Base.configurations.blank?
- @fixture_cache = {}
+ if pre_loaded_fixtures && !use_transactional_fixtures
+ raise RuntimeError, 'pre_loaded_fixtures requires use_transactional_fixtures'
+ end
- # Load fixtures once and begin transaction.
- if use_transactional_fixtures?
- if @@already_loaded_fixtures[self.class]
- @loaded_fixtures = @@already_loaded_fixtures[self.class]
- else
- load_fixtures
- @@already_loaded_fixtures[self.class] = @loaded_fixtures
- end
- ActiveRecord::Base.connection.increment_open_transactions
- ActiveRecord::Base.connection.begin_db_transaction
- ActiveRecord::Base.connection.transactional_fixtures = true
- # Load fixtures for every test.
+ @fixture_cache = {}
+ @@already_loaded_fixtures ||= {}
+
+ # Load fixtures once and begin transaction.
+ if run_in_transaction?
+ if @@already_loaded_fixtures[self.class]
+ @loaded_fixtures = @@already_loaded_fixtures[self.class]
else
- Fixtures.reset_cache
- @@already_loaded_fixtures[self.class] = nil
load_fixtures
+ @@already_loaded_fixtures[self.class] = @loaded_fixtures
end
-
- # Instantiate fixtures for every test if requested.
- instantiate_fixtures if use_instantiated_fixtures
+ ActiveRecord::Base.connection.increment_open_transactions
+ ActiveRecord::Base.connection.begin_db_transaction
+ ActiveRecord::Base.connection.transactional_fixtures = true
+ # Load fixtures for every test.
+ else
+ Fixtures.reset_cache
+ @@already_loaded_fixtures[self.class] = nil
+ load_fixtures
end
- def teardown_fixtures
- return unless defined?(ActiveRecord) && !ActiveRecord::Base.configurations.blank?
+ # Instantiate fixtures for every test if requested.
+ instantiate_fixtures if use_instantiated_fixtures
+ end
+
+ def teardown_fixtures
+ return unless defined?(ActiveRecord) && !ActiveRecord::Base.configurations.blank?
- unless use_transactional_fixtures?
- Fixtures.reset_cache
- end
+ unless run_in_transaction?
+ Fixtures.reset_cache
+ end
- # Rollback changes if a transaction is active.
- if use_transactional_fixtures? && ActiveRecord::Base.connection.open_transactions != 0
- ActiveRecord::Base.connection.rollback_db_transaction
- ActiveRecord::Base.connection.decrement_open_transactions
- ActiveRecord::Base.connection.transactional_fixtures = false
- end
- ActiveRecord::Base.clear_active_connections!
+ # Rollback changes if a transaction is active.
+ if run_in_transaction? && ActiveRecord::Base.connection.open_transactions != 0
+ ActiveRecord::Base.connection.rollback_db_transaction
+ ActiveRecord::Base.connection.decrement_open_transactions
+ ActiveRecord::Base.connection.transactional_fixtures = false
end
+ ActiveRecord::Base.clear_active_connections!
+ end
- private
- def load_fixtures
- @loaded_fixtures = {}
- fixtures = Fixtures.create_fixtures(fixture_path, fixture_table_names, fixture_class_names)
- unless fixtures.nil?
- if fixtures.instance_of?(Fixtures)
- @loaded_fixtures[fixtures.name] = fixtures
- else
- fixtures.each { |f| @loaded_fixtures[f.name] = f }
- end
+ private
+ def load_fixtures
+ @loaded_fixtures = {}
+ fixtures = Fixtures.create_fixtures(fixture_path, fixture_table_names, fixture_class_names)
+ unless fixtures.nil?
+ if fixtures.instance_of?(Fixtures)
+ @loaded_fixtures[fixtures.name] = fixtures
+ else
+ fixtures.each { |f| @loaded_fixtures[f.name] = f }
end
end
+ end
- # for pre_loaded_fixtures, only require the classes once. huge speed improvement
- @@required_fixture_classes = false
+ # for pre_loaded_fixtures, only require the classes once. huge speed improvement
+ @@required_fixture_classes = false
- def instantiate_fixtures
- if pre_loaded_fixtures
- raise RuntimeError, 'Load fixtures before instantiating them.' if Fixtures.all_loaded_fixtures.empty?
- unless @@required_fixture_classes
- self.class.require_fixture_classes Fixtures.all_loaded_fixtures.keys
- @@required_fixture_classes = true
- end
- Fixtures.instantiate_all_loaded_fixtures(self, load_instances?)
- else
- raise RuntimeError, 'Load fixtures before instantiating them.' if @loaded_fixtures.nil?
- @loaded_fixtures.each do |table_name, fixtures|
- Fixtures.instantiate_fixtures(self, table_name, fixtures, load_instances?)
- end
+ def instantiate_fixtures
+ if pre_loaded_fixtures
+ raise RuntimeError, 'Load fixtures before instantiating them.' if Fixtures.all_loaded_fixtures.empty?
+ unless @@required_fixture_classes
+ self.class.require_fixture_classes Fixtures.all_loaded_fixtures.keys
+ @@required_fixture_classes = true
+ end
+ Fixtures.instantiate_all_loaded_fixtures(self, load_instances?)
+ else
+ raise RuntimeError, 'Load fixtures before instantiating them.' if @loaded_fixtures.nil?
+ @loaded_fixtures.each do |table_name, fixtures|
+ Fixtures.instantiate_fixtures(self, table_name, fixtures, load_instances?)
end
end
+ end
- def load_instances?
- use_instantiated_fixtures != :no_instances
- end
- end
+ def load_instances?
+ use_instantiated_fixtures != :no_instances
+ end
end
end
diff --git a/activerecord/lib/active_record/locale/en-US.yml b/activerecord/lib/active_record/locale/en.yml
index 421f0ebd60..7e205435f7 100644
--- a/activerecord/lib/active_record/locale/en-US.yml
+++ b/activerecord/lib/active_record/locale/en.yml
@@ -1,4 +1,4 @@
-en-US:
+en:
activerecord:
errors:
# The values :model, :attribute and :value are always available for interpolation
diff --git a/activerecord/lib/active_record/serialization.rb b/activerecord/lib/active_record/serialization.rb
index 332cda1e16..870b4b2dd4 100644
--- a/activerecord/lib/active_record/serialization.rb
+++ b/activerecord/lib/active_record/serialization.rb
@@ -1,3 +1,5 @@
+require 'active_support/json'
+
module ActiveRecord #:nodoc:
module Serialization
class Serializer #:nodoc:
@@ -95,4 +97,4 @@ module ActiveRecord #:nodoc:
end
require 'active_record/serializers/xml_serializer'
-require 'active_record/serializers/json_serializer' \ No newline at end of file
+require 'active_record/serializers/json_serializer'
diff --git a/activerecord/lib/active_record/test_case.rb b/activerecord/lib/active_record/test_case.rb
index eabf06fc3b..149b93203e 100644
--- a/activerecord/lib/active_record/test_case.rb
+++ b/activerecord/lib/active_record/test_case.rb
@@ -1,21 +1,11 @@
require "active_support/test_case"
-module ActiveRecord
+module ActiveRecord
class TestCase < ActiveSupport::TestCase #:nodoc:
- self.fixture_path = FIXTURES_ROOT
- self.use_instantiated_fixtures = false
- self.use_transactional_fixtures = true
-
- def create_fixtures(*table_names, &block)
- Fixtures.create_fixtures(FIXTURES_ROOT, table_names, {}, &block)
- end
-
def assert_date_from_db(expected, actual, message = nil)
- # SQL Server doesn't have a separate column type just for dates,
+ # SybaseAdapter doesn't have a separate column type just for dates,
# so the time is in the string and incorrectly formatted
- if current_adapter?(:SQLServerAdapter)
- assert_equal expected.strftime("%Y/%m/%d 00:00:00"), actual.strftime("%Y/%m/%d 00:00:00")
- elsif current_adapter?(:SybaseAdapter)
+ 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
diff --git a/activerecord/lib/active_record/version.rb b/activerecord/lib/active_record/version.rb
index 2479b75789..6ac4bdc905 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 = 2
+ MINOR = 3
TINY = 0
STRING = [MAJOR, MINOR, TINY].join('.')