diff options
author | Pratik Naik <pratiknaik@gmail.com> | 2008-12-07 03:05:03 +0100 |
---|---|---|
committer | Pratik Naik <pratiknaik@gmail.com> | 2008-12-07 03:05:03 +0100 |
commit | 8f1c229571b4db8dda144bf6eaa193799309e817 (patch) | |
tree | 592710207a614428d5cb809f6e13c8b546b58969 /activerecord/lib | |
parent | 601e40e744f44fe8819be100a8c472ea161d13ab (diff) | |
parent | 9eca588bdfbb41f6b48477025d1cd8eea4a38296 (diff) | |
download | rails-8f1c229571b4db8dda144bf6eaa193799309e817.tar.gz rails-8f1c229571b4db8dda144bf6eaa193799309e817.tar.bz2 rails-8f1c229571b4db8dda144bf6eaa193799309e817.zip |
Merge commit 'mainstream/master'
Conflicts:
actionmailer/lib/action_mailer/base.rb
actionpack/lib/action_controller/base.rb
actionpack/lib/action_controller/mime_type.rb
railties/doc/guides/html/activerecord_validations_callbacks.html
railties/doc/guides/html/caching_with_rails.html
railties/doc/guides/html/command_line.html
railties/doc/guides/html/configuring.html
railties/doc/guides/html/creating_plugins.html
railties/doc/guides/html/finders.html
railties/doc/guides/html/routing_outside_in.html
railties/doc/guides/source/activerecord_validations_callbacks.txt
railties/doc/guides/source/caching_with_rails.txt
railties/doc/guides/source/command_line.txt
railties/doc/guides/source/creating_plugins/acts_as_yaffle.txt
railties/doc/guides/source/creating_plugins/controllers.txt
railties/doc/guides/source/creating_plugins/core_ext.txt
railties/doc/guides/source/creating_plugins/helpers.txt
railties/doc/guides/source/creating_plugins/index.txt
railties/doc/guides/source/creating_plugins/migration_generator.txt
railties/doc/guides/source/creating_plugins/models.txt
railties/doc/guides/source/creating_plugins/odds_and_ends.txt
railties/doc/guides/source/creating_plugins/routes.txt
railties/doc/guides/source/finders.txt
railties/doc/guides/source/routing_outside_in.txt
railties/doc/guides/source/testing_rails_applications.txt
Diffstat (limited to 'activerecord/lib')
-rw-r--r-- | activerecord/lib/active_record.rb | 82 | ||||
-rw-r--r-- | activerecord/lib/active_record/association_preload.rb | 2 | ||||
-rwxr-xr-x | activerecord/lib/active_record/associations.rb | 35 | ||||
-rw-r--r-- | activerecord/lib/active_record/associations/association_proxy.rb | 6 | ||||
-rw-r--r-- | activerecord/lib/active_record/associations/has_one_through_association.rb | 7 | ||||
-rwxr-xr-x | activerecord/lib/active_record/base.rb | 53 | ||||
-rw-r--r-- | activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb | 8 | ||||
-rwxr-xr-x | activerecord/lib/active_record/connection_adapters/abstract_adapter.rb | 3 | ||||
-rw-r--r-- | activerecord/lib/active_record/fixtures.rb | 285 | ||||
-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.rb | 4 | ||||
-rw-r--r-- | activerecord/lib/active_record/test_case.rb | 16 | ||||
-rw-r--r-- | activerecord/lib/active_record/version.rb | 4 |
13 files changed, 275 insertions, 232 deletions
diff --git a/activerecord/lib/active_record.rb b/activerecord/lib/active_record.rb index 219cd30f94..348e5b94af 100644 --- a/activerecord/lib/active_record.rb +++ b/activerecord/lib/active_record.rb @@ -31,51 +31,47 @@ rescue LoadError end end -require 'active_record/base' -require 'active_record/named_scope' -require 'active_record/observer' -require 'active_record/query_cache' -require 'active_record/validations' -require 'active_record/callbacks' -require 'active_record/reflection' -require 'active_record/associations' -require 'active_record/association_preload' -require 'active_record/aggregations' -require 'active_record/transactions' -require 'active_record/timestamp' -require 'active_record/locking/optimistic' -require 'active_record/locking/pessimistic' -require 'active_record/migration' -require 'active_record/schema' -require 'active_record/calculations' -require 'active_record/serialization' -require 'active_record/attribute_methods' -require 'active_record/dirty' -require 'active_record/dynamic_finder_match' +module ActiveRecord + # TODO: Review explicit loads to see if they will automatically be handled by the initilizer. + def self.load_all! + [Base, DynamicFinderMatch, ConnectionAdapters::AbstractAdapter] + end -ActiveRecord::Base.class_eval do - extend ActiveRecord::QueryCache - include ActiveRecord::Validations - include ActiveRecord::Locking::Optimistic - include ActiveRecord::Locking::Pessimistic - include ActiveRecord::AttributeMethods - include ActiveRecord::Dirty - include ActiveRecord::Callbacks - include ActiveRecord::Observing - include ActiveRecord::Timestamp - include ActiveRecord::Associations - include ActiveRecord::NamedScope - include ActiveRecord::AssociationPreload - include ActiveRecord::Aggregations - include ActiveRecord::Transactions - include ActiveRecord::Reflection - include ActiveRecord::Calculations - include ActiveRecord::Serialization -end + autoload :ActiveRecordError, 'active_record/base' + autoload :ConnectionNotEstablished, 'active_record/base' + + autoload :Aggregations, 'active_record/aggregations' + autoload :AssociationPreload, 'active_record/association_preload' + autoload :Associations, 'active_record/associations' + autoload :AttributeMethods, 'active_record/attribute_methods' + autoload :Base, 'active_record/base' + autoload :Calculations, 'active_record/calculations' + autoload :Callbacks, 'active_record/callbacks' + autoload :Dirty, 'active_record/dirty' + autoload :DynamicFinderMatch, 'active_record/dynamic_finder_match' + autoload :Migration, 'active_record/migration' + autoload :Migrator, 'active_record/migration' + autoload :NamedScope, 'active_record/named_scope' + autoload :Observing, 'active_record/observer' + autoload :QueryCache, 'active_record/query_cache' + autoload :Reflection, 'active_record/reflection' + autoload :Schema, 'active_record/schema' + autoload :SchemaDumper, 'active_record/schema_dumper' + autoload :Serialization, 'active_record/serialization' + autoload :TestCase, 'active_record/test_case' + autoload :Timestamp, 'active_record/timestamp' + autoload :Transactions, 'active_record/transactions' + autoload :Validations, 'active_record/validations' -require 'active_record/connection_adapters/abstract_adapter' + module Locking + autoload :Optimistic, 'active_record/locking/optimistic' + autoload :Pessimistic, 'active_record/locking/pessimistic' + end -require 'active_record/schema_dumper' + module ConnectionAdapters + autoload :AbstractAdapter, 'active_record/connection_adapters/abstract_adapter' + end +end require 'active_record/i18n_interpolation_deprecation' -I18n.load_path << File.dirname(__FILE__) + '/active_record/locale/en-US.yml' +I18n.load_path << File.dirname(__FILE__) + '/active_record/locale/en.yml' diff --git a/activerecord/lib/active_record/association_preload.rb b/activerecord/lib/active_record/association_preload.rb index 69300e5ce5..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]) diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb index 7f7819115c..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,7 +1613,7 @@ 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, :counter_sql, :delete_sql, :insert_sql, :before_add, :after_add, :before_remove, :after_remove, @@ -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..59f1d3b867 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], @@ -206,7 +207,10 @@ module ActiveRecord # Forwards any missing method call to the \target. def method_missing(method, *args) if load_target - raise NoMethodError unless @target.respond_to?(method) + unless @target.respond_to?(method) + message = "undefined method `#{method.to_s}' for \"#{@target}\":#{@target.class.to_s}" + raise NoMethodError, message + end if block_given? @target.send(method, *args) { |*block_args| yield(*block_args) } 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 57a380cb3c..5d614442c3 100755 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -515,6 +515,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: # @@ -537,6 +541,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) @@ -1640,15 +1645,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) @@ -1704,13 +1717,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 @@ -2036,6 +2051,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]) @@ -2051,7 +2076,7 @@ module ActiveRecord #:nodoc: end def scoped_methods #:nodoc: - Thread.current[:"#{self}_scoped_methods"] ||= [] + Thread.current[:"#{self}_scoped_methods"] ||= self.default_scoping.dup end def current_scoped_methods #:nodoc: @@ -2265,7 +2290,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) @@ -2328,7 +2353,7 @@ module ActiveRecord #:nodoc: # construct a path 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 +user_path+ construct # a path using the user's name instead of the user's id: @@ -2340,7 +2365,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 @@ -2984,4 +3009,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/connection_adapters/abstract/database_statements.rb b/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb index 97c6cd4331..189c6c7b5a 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) @@ -163,8 +163,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 f8fa969dc3..cab77fc031 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: diff --git a/activerecord/lib/active_record/fixtures.rb b/activerecord/lib/active_record/fixtures.rb index 114141a646..129306d335 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,186 +814,190 @@ 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 - # 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 + # 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 - 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 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 3c5a9b7df8..6ac4bdc905 100644 --- a/activerecord/lib/active_record/version.rb +++ b/activerecord/lib/active_record/version.rb @@ -1,8 +1,8 @@ module ActiveRecord module VERSION #:nodoc: MAJOR = 2 - MINOR = 2 - TINY = 1 + MINOR = 3 + TINY = 0 STRING = [MAJOR, MINOR, TINY].join('.') end |