diff options
author | Pratik Naik <pratiknaik@gmail.com> | 2010-03-12 16:00:01 +0000 |
---|---|---|
committer | Pratik Naik <pratiknaik@gmail.com> | 2010-03-12 16:00:01 +0000 |
commit | e68bfaf1fe1a7890a67af6f444281185f507cf9e (patch) | |
tree | 5e73caccdcdd65d0ac97f9eb92195928f30925f2 /activerecord | |
parent | ef6462c73003b28c8e060a06120abb9cd67b6d52 (diff) | |
parent | 16846553b8866eab2aa3b128a2a23a221a25f7e3 (diff) | |
download | rails-e68bfaf1fe1a7890a67af6f444281185f507cf9e.tar.gz rails-e68bfaf1fe1a7890a67af6f444281185f507cf9e.tar.bz2 rails-e68bfaf1fe1a7890a67af6f444281185f507cf9e.zip |
Merge remote branch 'mainstream/master'
Conflicts:
activerecord/lib/active_record/base.rb
railties/lib/rails/configuration.rb
railties/lib/rails/log_subscriber.rb
Diffstat (limited to 'activerecord')
34 files changed, 420 insertions, 343 deletions
diff --git a/activerecord/Rakefile b/activerecord/Rakefile index 8a414a751b..e638da0f3e 100644 --- a/activerecord/Rakefile +++ b/activerecord/Rakefile @@ -5,25 +5,10 @@ require 'rake/rdoctask' require 'rake/packagetask' require 'rake/gempackagetask' -require File.join(File.dirname(__FILE__), 'lib', 'active_record', 'version') require File.expand_path(File.dirname(__FILE__)) + "/test/config" -PKG_BUILD = ENV['PKG_BUILD'] ? '.' + ENV['PKG_BUILD'] : '' -PKG_NAME = 'activerecord' -PKG_VERSION = ActiveRecord::VERSION::STRING + PKG_BUILD -PKG_FILE_NAME = "#{PKG_NAME}-#{PKG_VERSION}" - -RELEASE_NAME = "REL #{PKG_VERSION}" - -RUBY_FORGE_PROJECT = "activerecord" -RUBY_FORGE_USER = "webster132" - MYSQL_DB_USER = 'rails' -PKG_FILES = FileList[ - "lib/**/*", "test/**/*", "examples/**/*", "doc/**/*", "[A-Z]*", "install.rb", "Rakefile" -].exclude(/\bCVS\b|~$/) - def run_without_aborting(*tasks) errors = [] diff --git a/activerecord/activerecord.gemspec b/activerecord/activerecord.gemspec index aeaafbb694..8b1ea8596a 100644 --- a/activerecord/activerecord.gemspec +++ b/activerecord/activerecord.gemspec @@ -1,9 +1,11 @@ +version = File.read(File.expand_path("../../RAILS_VERSION", __FILE__)).strip + Gem::Specification.new do |s| s.platform = Gem::Platform::RUBY s.name = 'activerecord' - s.version = '3.0.0.beta1' + s.version = version s.summary = 'Object-relational mapper framework (part of Rails).' - s.description = 'Object-relational mapper framework (part of Rails).' + s.description = 'Databases on Rails. Build a persistent domain model by mapping database tables to Ruby classes. Strong conventions for associations, validations, aggregations, migrations, and testing come baked-in.' s.required_ruby_version = '>= 1.8.7' s.author = 'David Heinemeier Hansson' @@ -18,7 +20,7 @@ Gem::Specification.new do |s| s.extra_rdoc_files = %w( README ) s.rdoc_options.concat ['--main', 'README'] - s.add_dependency('activesupport', '= 3.0.0.beta1') - s.add_dependency('activemodel', '= 3.0.0.beta1') - s.add_dependency('arel', '~> 0.2.1') + s.add_dependency('activesupport', version) + s.add_dependency('activemodel', version) + s.add_dependency('arel', '~> 0.3.1') end diff --git a/activerecord/lib/active_record.rb b/activerecord/lib/active_record.rb index b79da4565d..5942640c85 100644 --- a/activerecord/lib/active_record.rb +++ b/activerecord/lib/active_record.rb @@ -30,7 +30,6 @@ $:.unshift(activemodel_path) if File.directory?(activemodel_path) && !$:.include require 'active_support' require 'active_model' -require 'arel' module ActiveRecord extend ActiveSupport::Autoload @@ -38,8 +37,8 @@ module ActiveRecord eager_autoload do autoload :VERSION - autoload :ActiveRecordError, 'active_record/base' - autoload :ConnectionNotEstablished, 'active_record/base' + autoload :ActiveRecordError, 'active_record/errors' + autoload :ConnectionNotEstablished, 'active_record/errors' autoload :Aggregations autoload :AssociationPreload @@ -106,12 +105,16 @@ module ActiveRecord eager_autoload do autoload :AbstractAdapter + autoload :ConnectionManagement, "active_record/connection_adapters/abstract/connection_pool" end end autoload :TestCase autoload :TestFixtures, 'active_record/fixtures' + + base_hook do + Arel::Table.engine = Arel::Sql::Engine.new(self) + end end -Arel::Table.engine = Arel::Sql::Engine.new(ActiveRecord::Base) -I18n.load_path << File.dirname(__FILE__) + '/active_record/locale/en.yml' +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 a5b06460fe..6725d4e88b 100644 --- a/activerecord/lib/active_record/association_preload.rb +++ b/activerecord/lib/active_record/association_preload.rb @@ -126,7 +126,7 @@ module ActiveRecord parent_records.each do |parent_record| association_proxy = parent_record.send(reflection_name) association_proxy.loaded - association_proxy.target.push *Array.wrap(associated_record) + association_proxy.target.push(*Array.wrap(associated_record)) association_proxy.__send__(:set_inverse_instance, associated_record, parent_record) end diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb index 57785b4c93..b69577f8dd 100755 --- a/activerecord/lib/active_record/associations.rb +++ b/activerecord/lib/active_record/associations.rb @@ -1537,58 +1537,42 @@ module ActiveRecord # has_one associated objects, according to the defined :dependent rule. def configure_dependency_for_has_one(reflection) if reflection.options.include?(:dependent) - case reflection.options[:dependent] - when :destroy - method_name = "has_one_dependent_destroy_for_#{reflection.name}".to_sym - define_method(method_name) do - association = send(reflection.name) - association.destroy unless association.nil? - end - before_destroy method_name - when :delete - method_name = "has_one_dependent_delete_for_#{reflection.name}".to_sym + name = reflection.options[:dependent] + method_name = :"has_one_dependent_#{name}_for_#{reflection.name}" + + case name + when :destroy, :delete define_method(method_name) do - # Retrieve the associated object and delete it. The retrieval - # is necessary because there may be multiple associated objects - # with foreign keys pointing to this object, and we only want - # to delete the correct one, not all of them. association = send(reflection.name) - association.delete unless association.nil? + association.send(name) if association end - before_destroy method_name when :nullify - method_name = "has_one_dependent_nullify_for_#{reflection.name}".to_sym define_method(method_name) do association = send(reflection.name) - association.update_attribute(reflection.primary_key_name, nil) unless association.nil? + association.update_attribute(reflection.primary_key_name, nil) if association end - before_destroy method_name else raise ArgumentError, "The :dependent option expects either :destroy, :delete or :nullify (#{reflection.options[:dependent].inspect})" end + + before_destroy method_name end end def configure_dependency_for_belongs_to(reflection) if reflection.options.include?(:dependent) - case reflection.options[:dependent] - when :destroy - method_name = "belongs_to_dependent_destroy_for_#{reflection.name}".to_sym - define_method(method_name) do - association = send(reflection.name) - association.destroy unless association.nil? - end - after_destroy method_name - when :delete - method_name = "belongs_to_dependent_delete_for_#{reflection.name}".to_sym - define_method(method_name) do - association = send(reflection.name) - association.delete unless association.nil? - end - after_destroy method_name - else - raise ArgumentError, "The :dependent option expects either :destroy or :delete (#{reflection.options[:dependent].inspect})" + name = reflection.options[:dependent] + + unless [:destroy, :delete].include?(name) + raise ArgumentError, "The :dependent option expects either :destroy or :delete (#{reflection.options[:dependent].inspect})" + end + + method_name = :"belongs_to_dependent_#{name}_for_#{reflection.name}" + define_method(method_name) do + association = send(reflection.name) + association.send(name) if association end + after_destroy method_name end end diff --git a/activerecord/lib/active_record/attribute_methods/primary_key.rb b/activerecord/lib/active_record/attribute_methods/primary_key.rb index 365fdeb55a..095814b635 100644 --- a/activerecord/lib/active_record/attribute_methods/primary_key.rb +++ b/activerecord/lib/active_record/attribute_methods/primary_key.rb @@ -39,6 +39,22 @@ 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/base.rb b/activerecord/lib/active_record/base.rb index 318bfbe826..52587ef251 100755 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -11,174 +11,12 @@ require 'active_support/core_ext/hash/deep_merge' require 'active_support/core_ext/hash/indifferent_access' require 'active_support/core_ext/hash/slice' require 'active_support/core_ext/string/behavior' -require 'active_support/core_ext/object/metaclass' +require 'active_support/core_ext/object/singleton_class' require 'active_support/core_ext/module/delegation' +require 'arel' +require 'active_record/errors' module ActiveRecord #:nodoc: - # Generic Active Record exception class. - class ActiveRecordError < StandardError - end - - # Raised when the single-table inheritance mechanism fails to locate the subclass - # (for example due to improper usage of column that +inheritance_column+ points to). - class SubclassNotFound < ActiveRecordError #:nodoc: - end - - # Raised when an object assigned to an association has an incorrect type. - # - # class Ticket < ActiveRecord::Base - # has_many :patches - # end - # - # class Patch < ActiveRecord::Base - # belongs_to :ticket - # end - # - # # Comments are not patches, this assignment raises AssociationTypeMismatch. - # @ticket.patches << Comment.new(:content => "Please attach tests to your patch.") - class AssociationTypeMismatch < ActiveRecordError - end - - # Raised when unserialized object's type mismatches one specified for serializable field. - class SerializationTypeMismatch < ActiveRecordError - end - - # Raised when adapter not specified on connection (or configuration file <tt>config/database.yml</tt> misses adapter field). - class AdapterNotSpecified < ActiveRecordError - end - - # Raised when Active Record cannot find database adapter specified in <tt>config/database.yml</tt> or programmatically. - class AdapterNotFound < ActiveRecordError - end - - # Raised when connection to the database could not been established (for example when <tt>connection=</tt> is given a nil object). - class ConnectionNotEstablished < ActiveRecordError - end - - # Raised when Active Record cannot find record by given id or set of ids. - class RecordNotFound < ActiveRecordError - end - - # Raised by ActiveRecord::Base.save! and ActiveRecord::Base.create! methods when record cannot be - # saved because record is invalid. - class RecordNotSaved < ActiveRecordError - end - - # Raised when SQL statement cannot be executed by the database (for example, it's often the case for MySQL when Ruby driver used is too old). - class StatementInvalid < ActiveRecordError - end - - # Raised when SQL statement is invalid and the application gets a blank result. - class ThrowResult < ActiveRecordError - end - - # Parent class for all specific exceptions which wrap database driver exceptions - # provides access to the original exception also. - class WrappedDatabaseException < StatementInvalid - attr_reader :original_exception - - def initialize(message, original_exception) - super(message) - @original_exception = original_exception - end - end - - # Raised when a record cannot be inserted because it would violate a uniqueness constraint. - class RecordNotUnique < WrappedDatabaseException - end - - # Raised when a record cannot be inserted or updated because it references a non-existent record. - class InvalidForeignKey < WrappedDatabaseException - end - - # Raised when number of bind variables in statement given to <tt>:condition</tt> key (for example, when using +find+ method) - # does not match number of expected variables. - # - # For example, in - # - # Location.find :all, :conditions => ["lat = ? AND lng = ?", 53.7362] - # - # two placeholders are given but only one variable to fill them. - class PreparedStatementInvalid < ActiveRecordError - end - - # Raised on attempt to save stale record. Record is stale when it's being saved in another query after - # instantiation, for example, when two users edit the same wiki page and one starts editing and saves - # the page before the other. - # - # Read more about optimistic locking in ActiveRecord::Locking module RDoc. - class StaleObjectError < ActiveRecordError - end - - # Raised when association is being configured improperly or - # user tries to use offset and limit together with has_many or has_and_belongs_to_many associations. - class ConfigurationError < ActiveRecordError - end - - # Raised on attempt to update record that is instantiated as read only. - class ReadOnlyRecord < ActiveRecordError - end - - # <tt>ActiveRecord::Transactions::ClassMethods.transaction</tt> uses this exception - # to distinguish a deliberate rollback from other exceptional situations. - # Normally, raising an exception will cause the +transaction+ method to rollback - # the database transaction *and* pass on the exception. But if you raise an - # <tt>ActiveRecord::Rollback</tt> exception, then the database transaction will be rolled back, - # without passing on the exception. - # - # For example, you could do this in your controller to rollback a transaction: - # - # class BooksController < ActionController::Base - # def create - # Book.transaction do - # book = Book.new(params[:book]) - # book.save! - # if today_is_friday? - # # The system must fail on Friday so that our support department - # # won't be out of job. We silently rollback this transaction - # # without telling the user. - # raise ActiveRecord::Rollback, "Call tech support!" - # end - # end - # # ActiveRecord::Rollback is the only exception that won't be passed on - # # by ActiveRecord::Base.transaction, so this line will still be reached - # # even on Friday. - # redirect_to root_url - # end - # end - class Rollback < ActiveRecordError - end - - # Raised when attribute has a name reserved by Active Record (when attribute has name of one of Active Record instance methods). - class DangerousAttributeError < ActiveRecordError - end - - # Raised when unknown attributes are supplied via mass assignment. - class UnknownAttributeError < NoMethodError - end - - # Raised when an error occurred while doing a mass assignment to an attribute through the - # <tt>attributes=</tt> method. The exception has an +attribute+ property that is the name of the - # offending attribute. - class AttributeAssignmentError < ActiveRecordError - attr_reader :exception, :attribute - def initialize(message, exception, attribute) - @exception = exception - @attribute = attribute - @message = message - end - end - - # Raised when there are multiple errors while doing a mass assignment through the +attributes+ - # method. The exception has an +errors+ property that contains an array of AttributeAssignmentError - # objects, each corresponding to the error while assigning to an attribute. - class MultiparameterAssignmentErrors < ActiveRecordError - attr_reader :errors - def initialize(errors) - @errors = errors - end - end - # Active Record objects don't specify their attributes directly, but rather infer them from the table definition with # which they're linked. Adding, removing, and changing attributes and their type is done directly in the database. Any change # is instantly reflected in the Active Record objects. The mapping that binds a given Active Record class to a certain @@ -551,8 +389,8 @@ module ActiveRecord #:nodoc: class << self # Class methods def colorize_logging(*args) ActiveSupport::Deprecation.warn "ActiveRecord::Base.colorize_logging and " << - "config.active_record.colorize_logging are deprecated. Please use " << - "Rails::Subscriber.colorize_logging or config.colorize_logging instead", caller + "config.active_record.colorize_logging are deprecated. Please use " << + "Rails::LogSubscriber.colorize_logging or config.colorize_logging instead", caller end alias :colorize_logging= :colorize_logging @@ -1669,12 +1507,12 @@ module ActiveRecord #:nodoc: @attributes_cache = {} @new_record = true ensure_proper_type - self.attributes = attributes unless attributes.nil? if scope = self.class.send(:current_scoped_methods) create_with = scope.scope_for_create create_with.each { |att,value| self.send("#{att}=", value) } if create_with end + self.attributes = attributes unless attributes.nil? result = yield self if block_given? _run_initialize_callbacks @@ -1767,6 +1605,11 @@ module ActiveRecord #:nodoc: @destroyed || false end + # Returns if the record is persisted, i.e. it's not a new record and it was not destroyed. + def persisted? + !(new_record? || destroyed?) + end + # :call-seq: # save(options) # @@ -1816,7 +1659,7 @@ module ActiveRecord #:nodoc: # callbacks, Observer methods, or any <tt>:dependent</tt> association # options, use <tt>#destroy</tt>. def delete - self.class.delete(id) unless new_record? + self.class.delete(id) if persisted? @destroyed = true freeze end @@ -1824,7 +1667,7 @@ module ActiveRecord #:nodoc: # Deletes the record in the database and freezes this instance to reflect that no changes should # be made (since they can't be persisted). def destroy - unless new_record? + if persisted? self.class.unscoped.where(self.class.arel_table[self.class.primary_key].eq(id)).delete_all end @@ -1844,6 +1687,7 @@ module ActiveRecord #:nodoc: became.instance_variable_set("@attributes", @attributes) became.instance_variable_set("@attributes_cache", @attributes_cache) became.instance_variable_set("@new_record", new_record?) + became.instance_variable_set("@destroyed", destroyed?) became end @@ -1926,7 +1770,7 @@ module ActiveRecord #:nodoc: def reload(options = nil) clear_aggregation_cache clear_association_cache - @attributes.update(self.class.find(self.id, options).instance_variable_get('@attributes')) + @attributes.update(self.class.send(:with_exclusive_scope) { self.class.find(self.id, options) }.instance_variable_get('@attributes')) @attributes_cache = {} self end @@ -1995,10 +1839,9 @@ module ActiveRecord #:nodoc: # Returns a hash of all the attributes with their names as keys and the values of the attributes as values. def attributes - self.attribute_names.inject({}) do |attrs, name| - attrs[name] = read_attribute(name) - attrs - end + attrs = {} + attribute_names.each { |name| attrs[name] = read_attribute(name) } + attrs end # Returns an <tt>#inspect</tt>-like string for the value of the @@ -2042,8 +1885,7 @@ module ActiveRecord #:nodoc: def ==(comparison_object) comparison_object.equal?(self) || (comparison_object.instance_of?(self.class) && - comparison_object.id == id && - !comparison_object.new_record?) + comparison_object.id == id && !comparison_object.new_record?) end # Delegates to == @@ -2343,7 +2185,7 @@ module ActiveRecord #:nodoc: # Returns a comma-separated pair list, like "key1 = val1, key2 = val2". def comma_pair_list(hash) - hash.inject([]) { |list, pair| list << "#{pair.first} = #{pair.last}" }.join(", ") + hash.map { |k,v| "#{k} = #{v}" }.join(", ") end def quote_columns(quoter, hash) @@ -2397,8 +2239,10 @@ module ActiveRecord #:nodoc: include Aggregations, Transactions, Reflection, Serialization + NilClass.add_whiner(self) if NilClass.respond_to?(:add_whiner) end end # TODO: Remove this and make it work with LAZY flag require 'active_record/connection_adapters/abstract_adapter' +ActiveRecord.run_base_hooks(ActiveRecord::Base)
\ No newline at end of file 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 027d736484..abb695264e 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb @@ -113,7 +113,7 @@ module ActiveRecord def transaction(options = {}) options.assert_valid_keys :requires_new, :joinable - last_transaction_joinable = @transaction_joinable + last_transaction_joinable = defined?(@transaction_joinable) ? @transaction_joinable : nil if options.has_key?(:joinable) @transaction_joinable = options[:joinable] else 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 520f3c8c0c..64faaef4a0 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb @@ -319,16 +319,19 @@ module ActiveRecord def method_missing(symbol, *args) if symbol.to_s == 'xml' xml_column_fallback(args) + else + super end end def xml_column_fallback(*args) case @base.adapter_name.downcase - when 'sqlite', 'mysql' - options = args.extract_options! - column(args[0], :text, options) - end + when 'sqlite', 'mysql' + options = args.extract_options! + column(args[0], :text, options) end + end + # Appends a primary key definition to the table definition. # Can be called multiple times, but this is probably not a good idea. def primary_key(name) diff --git a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb index 7e80347f75..6ffffc8654 100755 --- a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb @@ -37,6 +37,7 @@ module ActiveRecord @@row_even = true def initialize(connection, logger = nil) #:nodoc: + @active = nil @connection, @logger = connection, logger @runtime = 0 @query_cache_enabled = false diff --git a/activerecord/lib/active_record/errors.rb b/activerecord/lib/active_record/errors.rb new file mode 100644 index 0000000000..cf5ddca2ba --- /dev/null +++ b/activerecord/lib/active_record/errors.rb @@ -0,0 +1,165 @@ +module ActiveRecord + # Generic Active Record exception class. + class ActiveRecordError < StandardError + end + + # Raised when the single-table inheritance mechanism fails to locate the subclass + # (for example due to improper usage of column that +inheritance_column+ points to). + class SubclassNotFound < ActiveRecordError #:nodoc: + end + + # Raised when an object assigned to an association has an incorrect type. + # + # class Ticket < ActiveRecord::Base + # has_many :patches + # end + # + # class Patch < ActiveRecord::Base + # belongs_to :ticket + # end + # + # # Comments are not patches, this assignment raises AssociationTypeMismatch. + # @ticket.patches << Comment.new(:content => "Please attach tests to your patch.") + class AssociationTypeMismatch < ActiveRecordError + end + + # Raised when unserialized object's type mismatches one specified for serializable field. + class SerializationTypeMismatch < ActiveRecordError + end + + # Raised when adapter not specified on connection (or configuration file <tt>config/database.yml</tt> misses adapter field). + class AdapterNotSpecified < ActiveRecordError + end + + # Raised when Active Record cannot find database adapter specified in <tt>config/database.yml</tt> or programmatically. + class AdapterNotFound < ActiveRecordError + end + + # Raised when connection to the database could not been established (for example when <tt>connection=</tt> is given a nil object). + class ConnectionNotEstablished < ActiveRecordError + end + + # Raised when Active Record cannot find record by given id or set of ids. + class RecordNotFound < ActiveRecordError + end + + # Raised by ActiveRecord::Base.save! and ActiveRecord::Base.create! methods when record cannot be + # saved because record is invalid. + class RecordNotSaved < ActiveRecordError + end + + # Raised when SQL statement cannot be executed by the database (for example, it's often the case for MySQL when Ruby driver used is too old). + class StatementInvalid < ActiveRecordError + end + + # Raised when SQL statement is invalid and the application gets a blank result. + class ThrowResult < ActiveRecordError + end + + # Parent class for all specific exceptions which wrap database driver exceptions + # provides access to the original exception also. + class WrappedDatabaseException < StatementInvalid + attr_reader :original_exception + + def initialize(message, original_exception) + super(message) + @original_exception = original_exception + end + end + + # Raised when a record cannot be inserted because it would violate a uniqueness constraint. + class RecordNotUnique < WrappedDatabaseException + end + + # Raised when a record cannot be inserted or updated because it references a non-existent record. + class InvalidForeignKey < WrappedDatabaseException + end + + # Raised when number of bind variables in statement given to <tt>:condition</tt> key (for example, when using +find+ method) + # does not match number of expected variables. + # + # For example, in + # + # Location.find :all, :conditions => ["lat = ? AND lng = ?", 53.7362] + # + # two placeholders are given but only one variable to fill them. + class PreparedStatementInvalid < ActiveRecordError + end + + # Raised on attempt to save stale record. Record is stale when it's being saved in another query after + # instantiation, for example, when two users edit the same wiki page and one starts editing and saves + # the page before the other. + # + # Read more about optimistic locking in ActiveRecord::Locking module RDoc. + class StaleObjectError < ActiveRecordError + end + + # Raised when association is being configured improperly or + # user tries to use offset and limit together with has_many or has_and_belongs_to_many associations. + class ConfigurationError < ActiveRecordError + end + + # Raised on attempt to update record that is instantiated as read only. + class ReadOnlyRecord < ActiveRecordError + end + + # ActiveRecord::Transactions::ClassMethods.transaction uses this exception + # to distinguish a deliberate rollback from other exceptional situations. + # Normally, raising an exception will cause the +transaction+ method to rollback + # the database transaction *and* pass on the exception. But if you raise an + # ActiveRecord::Rollback exception, then the database transaction will be rolled back, + # without passing on the exception. + # + # For example, you could do this in your controller to rollback a transaction: + # + # class BooksController < ActionController::Base + # def create + # Book.transaction do + # book = Book.new(params[:book]) + # book.save! + # if today_is_friday? + # # The system must fail on Friday so that our support department + # # won't be out of job. We silently rollback this transaction + # # without telling the user. + # raise ActiveRecord::Rollback, "Call tech support!" + # end + # end + # # ActiveRecord::Rollback is the only exception that won't be passed on + # # by ActiveRecord::Base.transaction, so this line will still be reached + # # even on Friday. + # redirect_to root_url + # end + # end + class Rollback < ActiveRecordError + end + + # Raised when attribute has a name reserved by Active Record (when attribute has name of one of Active Record instance methods). + class DangerousAttributeError < ActiveRecordError + end + + # Raised when unknown attributes are supplied via mass assignment. + class UnknownAttributeError < NoMethodError + end + + # Raised when an error occurred while doing a mass assignment to an attribute through the + # <tt>attributes=</tt> method. The exception has an +attribute+ property that is the name of the + # offending attribute. + class AttributeAssignmentError < ActiveRecordError + attr_reader :exception, :attribute + def initialize(message, exception, attribute) + @exception = exception + @attribute = attribute + @message = message + end + end + + # Raised when there are multiple errors while doing a mass assignment through the +attributes+ + # method. The exception has an +errors+ property that contains an array of AttributeAssignmentError + # objects, each corresponding to the error while assigning to an attribute. + class MultiparameterAssignmentErrors < ActiveRecordError + attr_reader :errors + def initialize(errors) + @errors = errors + end + end +end
\ No newline at end of file diff --git a/activerecord/lib/active_record/migration.rb b/activerecord/lib/active_record/migration.rb index 068d2a25b2..fd5ffc6d77 100644 --- a/activerecord/lib/active_record/migration.rb +++ b/activerecord/lib/active_record/migration.rb @@ -1,4 +1,4 @@ -require 'active_support/core_ext/object/metaclass' +require 'active_support/core_ext/object/singleton_class' module ActiveRecord # Exception that can be raised to stop migrations from going backwards. @@ -303,7 +303,7 @@ module ActiveRecord case sym when :up, :down - metaclass.send(:alias_method_chain, sym, "benchmarks") + singleton_class.send(:alias_method_chain, sym, "benchmarks") end ensure @ignore_new_methods = false diff --git a/activerecord/lib/active_record/named_scope.rb b/activerecord/lib/active_record/named_scope.rb index ff6c041ef4..394e1587e1 100644 --- a/activerecord/lib/active_record/named_scope.rb +++ b/activerecord/lib/active_record/named_scope.rb @@ -1,6 +1,6 @@ require 'active_support/core_ext/array' require 'active_support/core_ext/hash/except' -require 'active_support/core_ext/object/metaclass' +require 'active_support/core_ext/object/singleton_class' module ActiveRecord module NamedScope @@ -26,7 +26,7 @@ module ActiveRecord if options.present? Scope.init(self, options, &block) else - current_scoped_methods ? unscoped.merge(current_scoped_methods) : unscoped.spawn + current_scoped_methods ? unscoped.merge(current_scoped_methods) : unscoped.clone end end @@ -112,7 +112,7 @@ module ActiveRecord options.call(*args) end, &block) end - metaclass.instance_eval do + singleton_class.instance_eval do define_method name do |*args| scopes[name].call(self, *args) end diff --git a/activerecord/lib/active_record/railtie.rb b/activerecord/lib/active_record/railtie.rb index e70b0d1bfb..60addd46c6 100644 --- a/activerecord/lib/active_record/railtie.rb +++ b/activerecord/lib/active_record/railtie.rb @@ -20,35 +20,43 @@ module ActiveRecord end # TODO If we require the wrong file, the error never comes up. - require "active_record/railties/subscriber" - subscriber ActiveRecord::Railties::Subscriber.new + require "active_record/railties/log_subscriber" + log_subscriber ActiveRecord::Railties::LogSubscriber.new initializer "active_record.initialize_timezone" do - ActiveRecord::Base.time_zone_aware_attributes = true - ActiveRecord::Base.default_timezone = :utc + ActiveRecord.base_hook do + self.time_zone_aware_attributes = true + self.default_timezone = :utc + end end initializer "active_record.logger" do - ActiveRecord::Base.logger ||= ::Rails.logger + ActiveRecord.base_hook { self.logger ||= ::Rails.logger } end initializer "active_record.set_configs" do |app| - app.config.active_record.each do |k,v| - ActiveRecord::Base.send "#{k}=", v + ActiveRecord.base_hook do + app.config.active_record.each do |k,v| + send "#{k}=", v + end end end # This sets the database configuration from Configuration#database_configuration # and then establishes the connection. initializer "active_record.initialize_database" do |app| - ActiveRecord::Base.configurations = app.config.database_configuration - ActiveRecord::Base.establish_connection + ActiveRecord.base_hook do + self.configurations = app.config.database_configuration + establish_connection + end end # Expose database runtime to controller for logging. initializer "active_record.log_runtime" do |app| require "active_record/railties/controller_runtime" - ActionController::Base.send :include, ActiveRecord::Railties::ControllerRuntime + ActionController.base_hook do + include ActiveRecord::Railties::ControllerRuntime + end end # Setup database middleware after initializers have run @@ -64,18 +72,22 @@ module ActiveRecord end initializer "active_record.load_observers" do - ActiveRecord::Base.instantiate_observers + ActiveRecord.base_hook { instantiate_observers } - ActionDispatch::Callbacks.to_prepare(:activerecord_instantiate_observers) do - ActiveRecord::Base.instantiate_observers + ActiveRecord.base_hook do + ActionDispatch::Callbacks.to_prepare(:activerecord_instantiate_observers) do + ActiveRecord::Base.instantiate_observers + end end end initializer "active_record.set_dispatch_hooks", :before => :set_clear_dependencies_hook do |app| - unless app.config.cache_classes - ActionDispatch::Callbacks.after do - ActiveRecord::Base.reset_subclasses - ActiveRecord::Base.clear_reloadable_connections! + ActiveRecord.base_hook do + unless app.config.cache_classes + ActionDispatch::Callbacks.after do + ActiveRecord::Base.reset_subclasses + ActiveRecord::Base.clear_reloadable_connections! + end end end end diff --git a/activerecord/lib/active_record/railties/databases.rake b/activerecord/lib/active_record/railties/databases.rake index ed7d2a045e..fa6caa4910 100644 --- a/activerecord/lib/active_record/railties/databases.rake +++ b/activerecord/lib/active_record/railties/databases.rake @@ -109,7 +109,7 @@ namespace :db do # Only connect to local databases local_database?(config) { drop_database(config) } rescue Exception => e - puts "Couldn't drop #{config['database']} : #{e.inspect}" + $stderr.puts "Couldn't drop #{config['database']} : #{e.inspect}" end end end @@ -121,7 +121,7 @@ namespace :db do begin drop_database(config) rescue Exception => e - puts "Couldn't drop #{config['database']} : #{e.inspect}" + $stderr.puts "Couldn't drop #{config['database']} : #{e.inspect}" end end @@ -129,7 +129,7 @@ namespace :db do if %w( 127.0.0.1 localhost ).include?(config['host']) || config['host'].blank? yield else - puts "This task only modifies local databases. #{config['database']} is on a remote host." + $stderr.puts "This task only modifies local databases. #{config['database']} is on a remote host." end end @@ -204,7 +204,7 @@ namespace :db do ActiveRecord::Base.establish_connection(config) puts ActiveRecord::Base.connection.encoding else - puts 'sorry, your database adapter is not supported yet, feel free to submit a patch' + $stderr.puts 'sorry, your database adapter is not supported yet, feel free to submit a patch' end end @@ -216,7 +216,7 @@ namespace :db do ActiveRecord::Base.establish_connection(config) puts ActiveRecord::Base.connection.collation else - puts 'sorry, your database adapter is not supported yet, feel free to submit a patch' + $stderr.puts 'sorry, your database adapter is not supported yet, feel free to submit a patch' end end diff --git a/activerecord/lib/active_record/railties/subscriber.rb b/activerecord/lib/active_record/railties/log_subscriber.rb index fd873dbff8..48b25032ce 100644 --- a/activerecord/lib/active_record/railties/subscriber.rb +++ b/activerecord/lib/active_record/railties/log_subscriber.rb @@ -1,6 +1,6 @@ module ActiveRecord module Railties - class Subscriber < Rails::Subscriber + class LogSubscriber < Rails::LogSubscriber def sql(event) name = '%s (%.1fms)' % [event.payload[:name], event.duration] sql = event.payload[:sql].squeeze(' ') diff --git a/activerecord/lib/active_record/relation.rb b/activerecord/lib/active_record/relation.rb index 7bc3d3bf33..aca4629dd8 100644 --- a/activerecord/lib/active_record/relation.rb +++ b/activerecord/lib/active_record/relation.rb @@ -21,6 +21,10 @@ module ActiveRecord with_create_scope { @klass.new(*args, &block) } end + def initialize_copy(other) + reset + end + alias build new def create(*args, &block) diff --git a/activerecord/lib/active_record/relation/predicate_builder.rb b/activerecord/lib/active_record/relation/predicate_builder.rb index 65e5c0495c..7e83eccbb5 100644 --- a/activerecord/lib/active_record/relation/predicate_builder.rb +++ b/activerecord/lib/active_record/relation/predicate_builder.rb @@ -20,7 +20,7 @@ module ActiveRecord table = Arel::Table.new(table_name, :engine => @engine) end - attribute = table[column] || Arel::Attribute.new(table, column.to_sym) + attribute = table[column] case value when Array, ActiveRecord::Associations::AssociationCollection, ActiveRecord::NamedScope::Scope diff --git a/activerecord/lib/active_record/relation/query_methods.rb b/activerecord/lib/active_record/relation/query_methods.rb index 0266700f66..e00d9cdf27 100644 --- a/activerecord/lib/active_record/relation/query_methods.rb +++ b/activerecord/lib/active_record/relation/query_methods.rb @@ -8,7 +8,7 @@ module ActiveRecord class_eval <<-CEVAL def #{query_method}(*args) - new_relation = spawn + new_relation = clone value = Array.wrap(args.flatten).reject {|x| x.blank? } new_relation.#{query_method}_values += value if value.present? new_relation @@ -19,7 +19,7 @@ module ActiveRecord [:where, :having].each do |query_method| class_eval <<-CEVAL def #{query_method}(*args) - new_relation = spawn + new_relation = clone value = build_where(*args) new_relation.#{query_method}_values += [*value] if value.present? new_relation @@ -32,7 +32,7 @@ module ActiveRecord class_eval <<-CEVAL def #{query_method}(value = true) - new_relation = spawn + new_relation = clone new_relation.#{query_method}_value = value new_relation end @@ -41,12 +41,12 @@ module ActiveRecord end def lock(locks = true) - relation = spawn + relation = clone case locks when String, TrueClass, NilClass - spawn.tap {|new_relation| new_relation.lock_value = locks || true } + clone.tap {|new_relation| new_relation.lock_value = locks || true } else - spawn.tap {|new_relation| new_relation.lock_value = false } + clone.tap {|new_relation| new_relation.lock_value = false } end end @@ -174,7 +174,7 @@ module ActiveRecord arel = arel.lock when String arel = arel.lock(@lock_value) - end + end if defined?(@lock_value) arel end @@ -184,16 +184,16 @@ module ActiveRecord builder = PredicateBuilder.new(table.engine) - conditions = if [String, Array].include?(args.first.class) - @klass.send(:sanitize_sql, args.size > 1 ? args : args.first) - elsif args.first.is_a?(Hash) - attributes = @klass.send(:expand_hash_conditions_for_aggregates, args.first) + opts = args.first + case opts + when String, Array + @klass.send(:sanitize_sql, args.size > 1 ? args : opts) + when Hash + attributes = @klass.send(:expand_hash_conditions_for_aggregates, opts) builder.build_from_hash(attributes, table) else - args.first + opts end - - conditions end private diff --git a/activerecord/lib/active_record/relation/spawn_methods.rb b/activerecord/lib/active_record/relation/spawn_methods.rb index cccf413e67..a18380f01c 100644 --- a/activerecord/lib/active_record/relation/spawn_methods.rb +++ b/activerecord/lib/active_record/relation/spawn_methods.rb @@ -1,11 +1,7 @@ module ActiveRecord module SpawnMethods - def spawn - clone.reset - end - def merge(r) - merged_relation = spawn + merged_relation = clone return merged_relation unless r merged_relation = merged_relation.eager_load(r.eager_load_values).preload(r.preload_values).includes(r.includes_values) @@ -83,7 +79,7 @@ module ActiveRecord :order, :select, :readonly, :group, :having, :from, :lock ] def apply_finder_options(options) - relation = spawn + relation = clone return relation unless options options.assert_valid_keys(VALID_FIND_OPTIONS) diff --git a/activerecord/lib/active_record/version.rb b/activerecord/lib/active_record/version.rb index 286ecd0289..eaf5dc6545 100644 --- a/activerecord/lib/active_record/version.rb +++ b/activerecord/lib/active_record/version.rb @@ -2,8 +2,9 @@ module ActiveRecord module VERSION #:nodoc: MAJOR = 3 MINOR = 0 - TINY = "0.beta1" + TINY = 0 + BUILD = "beta1" - STRING = [MAJOR, MINOR, TINY].join('.') + STRING = [MAJOR, MINOR, TINY, BUILD].join('.') end end diff --git a/activerecord/test/cases/ar_schema_test.rb b/activerecord/test/cases/ar_schema_test.rb index 4c1589d965..665c387d5d 100644 --- a/activerecord/test/cases/ar_schema_test.rb +++ b/activerecord/test/cases/ar_schema_test.rb @@ -27,6 +27,16 @@ if ActiveRecord::Base.connection.supports_migrations? assert_nothing_raised { @connection.select_all "SELECT * FROM schema_migrations" } assert_equal 7, ActiveRecord::Migrator::current_version end + + def test_schema_raises_an_error_for_invalid_column_ntype + assert_raise NoMethodError do + ActiveRecord::Schema.define(:version => 8) do + create_table :vegetables do |t| + t.unknown :color + end + end + end + end 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 2a77eed1b5..41a23d7f61 100644 --- a/activerecord/test/cases/associations/belongs_to_associations_test.rb +++ b/activerecord/test/cases/associations/belongs_to_associations_test.rb @@ -18,7 +18,8 @@ require 'models/essay' class BelongsToAssociationsTest < ActiveRecord::TestCase fixtures :accounts, :companies, :developers, :projects, :topics, - :developers_projects, :computers, :authors, :posts, :tags, :taggings, :comments + :developers_projects, :computers, :authors, :author_addresses, + :posts, :tags, :taggings, :comments def test_belongs_to Client.find(3).firm.name @@ -346,14 +347,14 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase assert_raise(ActiveRecord::ReadOnlyRecord) { companies(:first_client).readonly_firm.save! } assert companies(:first_client).readonly_firm.readonly? end - + def test_polymorphic_assignment_foreign_type_field_updating # should update when assigning a saved record sponsor = Sponsor.new member = Member.create sponsor.sponsorable = member assert_equal "Member", sponsor.sponsorable_type - + # should update when assigning a new record sponsor = Sponsor.new member = Member.new @@ -374,15 +375,15 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase essay.writer = writer assert_equal "Author", essay.writer_type end - + def test_polymorphic_assignment_updates_foreign_id_field_for_new_and_saved_records sponsor = Sponsor.new saved_member = Member.create new_member = Member.new - + sponsor.sponsorable = saved_member assert_equal saved_member.id, sponsor.sponsorable_id - + sponsor.sponsorable = new_member assert_equal nil, sponsor.sponsorable_id end @@ -424,4 +425,23 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase Account.find(@account.id, :include => :firm).save! end end + + def test_dependent_delete_and_destroy_with_belongs_to + author_address = author_addresses(:david_address) + author_address_extra = author_addresses(:david_address_extra) + assert_equal [], AuthorAddress.destroyed_author_address_ids + + assert_difference "AuthorAddress.count", -2 do + authors(:david).destroy + end + + assert_equal [], AuthorAddress.find_all_by_id([author_address.id, author_address_extra.id]) + assert_equal [author_address.id], AuthorAddress.destroyed_author_address_ids + end + + def test_invalid_belongs_to_dependent_option_raises_exception + assert_raise ArgumentError do + Author.belongs_to :special_author_address, :dependent => :nullify + end + end end diff --git a/activerecord/test/cases/associations/has_many_associations_test.rb b/activerecord/test/cases/associations/has_many_associations_test.rb index ce7eedbb54..54624e79ce 100644 --- a/activerecord/test/cases/associations/has_many_associations_test.rb +++ b/activerecord/test/cases/associations/has_many_associations_test.rb @@ -14,7 +14,7 @@ require 'models/tagging' class HasManyAssociationsTest < ActiveRecord::TestCase fixtures :accounts, :categories, :companies, :developers, :projects, - :developers_projects, :topics, :authors, :comments, :author_addresses, + :developers_projects, :topics, :authors, :comments, :people, :posts, :readers, :taggings def setup @@ -684,24 +684,6 @@ class HasManyAssociationsTest < ActiveRecord::TestCase assert_equal 'Microsoft', another_ms_client.name end - def test_dependent_delete_and_destroy_with_belongs_to - author_address = author_addresses(:david_address) - assert_equal [], AuthorAddress.destroyed_author_address_ids[authors(:david).id] - - assert_difference "AuthorAddress.count", -2 do - authors(:david).destroy - end - - assert_equal nil, AuthorAddress.find_by_id(authors(:david).author_address_id) - assert_equal nil, AuthorAddress.find_by_id(authors(:david).author_address_extra_id) - end - - def test_invalid_belongs_to_dependent_option_raises_exception - assert_raise ArgumentError do - Author.belongs_to :special_author_address, :dependent => :nullify - end - end - def test_clearing_without_initial_access firm = companies(:first_firm) diff --git a/activerecord/test/cases/associations/has_one_associations_test.rb b/activerecord/test/cases/associations/has_one_associations_test.rb index d359ad48c5..d5dbb88886 100644 --- a/activerecord/test/cases/associations/has_one_associations_test.rb +++ b/activerecord/test/cases/associations/has_one_associations_test.rb @@ -14,7 +14,7 @@ class HasOneAssociationsTest < ActiveRecord::TestCase assert_equal companies(:first_firm).account, Account.find(1) assert_equal Account.find(1).credit_limit, companies(:first_firm).account.credit_limit end - + def test_has_one_cache_nils firm = companies(:another_firm) assert_queries(1) { assert_nil firm.account } @@ -96,7 +96,7 @@ class HasOneAssociationsTest < ActiveRecord::TestCase assert_nil Account.find(old_account_id).firm_id end - def test_association_changecalls_delete + def test_association_change_calls_delete companies(:first_firm).deletable_account = Account.new assert_equal [], Account.destroyed_account_ids[companies(:first_firm).id] end diff --git a/activerecord/test/cases/base_test.rb b/activerecord/test/cases/base_test.rb index 1441b4278d..e3047fe873 100755 --- a/activerecord/test/cases/base_test.rb +++ b/activerecord/test/cases/base_test.rb @@ -1330,11 +1330,6 @@ class BasicsTest < ActiveRecord::TestCase end def test_destroyed_returns_boolean - developer = Developer.new - assert_equal developer.destroyed?, false - developer.destroy - assert_equal developer.destroyed?, true - developer = Developer.first assert_equal developer.destroyed?, false developer.destroy @@ -1346,6 +1341,23 @@ class BasicsTest < ActiveRecord::TestCase assert_equal developer.destroyed?, true end + def test_persisted_returns_boolean + developer = Developer.new(:name => "Jose") + assert_equal developer.persisted?, false + developer.save! + assert_equal developer.persisted?, true + + developer = Developer.first + assert_equal developer.persisted?, true + developer.destroy + assert_equal developer.persisted?, false + + developer = Developer.last + assert_equal developer.persisted?, true + developer.delete + assert_equal developer.persisted?, false + end + def test_clone topic = Topic.find(1) cloned_topic = nil @@ -1711,6 +1723,12 @@ class BasicsTest < ActiveRecord::TestCase assert_equal t1.title, t2.title end + def test_reload_with_exclusive_scope + dev = DeveloperCalledDavid.first + dev.update_attributes!( :name => "NotDavid" ) + assert_equal dev, dev.reload + end + def test_define_attr_method_with_value k = Class.new( ActiveRecord::Base ) k.send(:define_attr_method, :table_name, "foo") diff --git a/activerecord/test/cases/calculations_test.rb b/activerecord/test/cases/calculations_test.rb index e6d56a7193..28a1ae5feb 100644 --- a/activerecord/test/cases/calculations_test.rb +++ b/activerecord/test/cases/calculations_test.rb @@ -38,12 +38,12 @@ class CalculationsTest < ActiveRecord::TestCase end def test_should_get_maximum_of_field_with_include - assert_equal 50, Account.maximum(:credit_limit, :include => :firm, :conditions => "companies.name != 'Summit'") + assert_equal 55, Account.maximum(:credit_limit, :include => :firm, :conditions => "companies.name != 'Summit'") end def test_should_get_maximum_of_field_with_scoped_include Account.send :with_scope, :find => { :include => :firm, :conditions => "companies.name != 'Summit'" } do - assert_equal 50, Account.maximum(:credit_limit) + assert_equal 55, Account.maximum(:credit_limit) end end diff --git a/activerecord/test/cases/helper.rb b/activerecord/test/cases/helper.rb index 9e8bfbbee8..e831ebf36c 100644 --- a/activerecord/test/cases/helper.rb +++ b/activerecord/test/cases/helper.rb @@ -1,11 +1,15 @@ require File.expand_path('../../../../load_paths', __FILE__) +lib = File.expand_path("#{File.dirname(__FILE__)}/../../lib") +$:.unshift(lib) unless $:.include?('lib') || $:.include?(lib) + require 'config' require 'test/unit' require 'stringio' require 'active_record' +require 'active_support/dependencies' require 'connection' begin diff --git a/activerecord/test/cases/subscriber_test.rb b/activerecord/test/cases/log_subscriber_test.rb index 5328d4468b..f3b94eb829 100644 --- a/activerecord/test/cases/subscriber_test.rb +++ b/activerecord/test/cases/log_subscriber_test.rb @@ -1,15 +1,16 @@ require "cases/helper" require "models/developer" -require "rails/subscriber/test_helper" -require "active_record/railties/subscriber" +require "rails/log_subscriber/test_helper" +require "active_record/railties/log_subscriber" -class SubscriberTest < ActiveSupport::TestCase - include Rails::Subscriber::TestHelper - Rails::Subscriber.add(:active_record, ActiveRecord::Railties::Subscriber.new) +class LogSubscriberTest < ActiveSupport::TestCase + include Rails::LogSubscriber::TestHelper def setup @old_logger = ActiveRecord::Base.logger super + + Rails::LogSubscriber.add(:active_record, ActiveRecord::Railties::LogSubscriber.new) end def teardown diff --git a/activerecord/test/cases/method_scoping_test.rb b/activerecord/test/cases/method_scoping_test.rb index 1081aa40a9..3151457440 100644 --- a/activerecord/test/cases/method_scoping_test.rb +++ b/activerecord/test/cases/method_scoping_test.rb @@ -663,6 +663,16 @@ class DefaultScopingTest < ActiveRecord::TestCase assert_equal 2, posts.count assert_equal posts(:thinking), posts.first end + + def test_create_attribute_overwrites_default_scoping + assert_equal 'David', PoorDeveloperCalledJamis.create!(:name => 'David').name + assert_equal 200000, PoorDeveloperCalledJamis.create!(:name => 'David', :salary => 200000).salary + end + + def test_create_attribute_overwrites_default_values + assert_equal nil, PoorDeveloperCalledJamis.create!(:salary => nil).salary + assert_equal 50000, PoorDeveloperCalledJamis.create!(:name => 'David').salary + end end =begin diff --git a/activerecord/test/cases/pk_test.rb b/activerecord/test/cases/pk_test.rb index c121e0aa0f..5bba1d5625 100644 --- a/activerecord/test/cases/pk_test.rb +++ b/activerecord/test/cases/pk_test.rb @@ -9,6 +9,20 @@ require 'models/mixed_case_monkey' class PrimaryKeysTest < ActiveRecord::TestCase fixtures :topics, :subscribers, :movies, :mixed_case_monkeys + def test_to_key_with_default_primary_key + topic = Topic.new + assert topic.to_key.nil? + topic = Topic.find(1) + assert_equal topic.to_key, [1] + end + + def test_to_key_with_customized_primary_key + keyboard = Keyboard.new + assert keyboard.to_key.nil? + keyboard.save + assert_equal keyboard.to_key, [keyboard.id] + end + def test_integer_key topic = Topic.find(1) assert_equal(topics(:first).author_name, topic.author_name) diff --git a/activerecord/test/models/author.rb b/activerecord/test/models/author.rb index 7cbc6e803f..025f6207f8 100644 --- a/activerecord/test/models/author.rb +++ b/activerecord/test/models/author.rb @@ -35,7 +35,7 @@ class Author < ActiveRecord::Base has_many :ordered_uniq_comments, :through => :posts, :source => :comments, :uniq => true, :order => 'comments.id' has_many :ordered_uniq_comments_desc, :through => :posts, :source => :comments, :uniq => true, :order => 'comments.id DESC' has_many :readonly_comments, :through => :posts, :source => :comments, :readonly => true - + has_many :special_posts has_many :special_post_comments, :through => :special_posts, :source => :comments @@ -130,14 +130,11 @@ class AuthorAddress < ActiveRecord::Base has_one :author def self.destroyed_author_address_ids - @destroyed_author_address_ids ||= Hash.new { |h,k| h[k] = [] } + @destroyed_author_address_ids ||= [] end before_destroy do |author_address| - if author_address.author - AuthorAddress.destroyed_author_address_ids[author_address.author.id] << author_address.id - end - true + AuthorAddress.destroyed_author_address_ids << author_address.id end end diff --git a/activerecord/test/models/company.rb b/activerecord/test/models/company.rb index df5fd10b6b..f31d5f87e5 100644 --- a/activerecord/test/models/company.rb +++ b/activerecord/test/models/company.rb @@ -82,7 +82,7 @@ class Firm < Company has_one :account_using_primary_key, :primary_key => "firm_id", :class_name => "Account", :order => "id" has_one :account_using_foreign_and_primary_keys, :foreign_key => "firm_name", :primary_key => "name", :class_name => "Account" has_one :deletable_account, :foreign_key => "firm_id", :class_name => "Account", :dependent => :delete - + has_one :account_limit_500_with_hash_conditions, :foreign_key => "firm_id", :class_name => "Account", :conditions => { :credit_limit => 500 } has_one :unautosaved_account, :foreign_key => "firm_id", :class_name => 'Account', :autosave => false @@ -155,7 +155,7 @@ class VerySpecialClient < SpecialClient end class Account < ActiveRecord::Base - belongs_to :firm + belongs_to :firm, :class_name => 'Company' belongs_to :unautosaved_firm, :foreign_key => "firm_id", :class_name => "Firm", :autosave => false def self.destroyed_account_ids diff --git a/activerecord/test/models/developer.rb b/activerecord/test/models/developer.rb index e7a1e110d7..e35de3b9b0 100644 --- a/activerecord/test/models/developer.rb +++ b/activerecord/test/models/developer.rb @@ -99,3 +99,8 @@ class DeveloperCalledJamis < ActiveRecord::Base self.table_name = 'developers' default_scope :conditions => { :name => 'Jamis' } end + +class PoorDeveloperCalledJamis < ActiveRecord::Base + self.table_name = 'developers' + default_scope :conditions => { :name => 'Jamis', :salary => 50000 } +end
\ No newline at end of file |