From b60c8a573e63998b4aa3f93a1728bb9b6c6fb8f9 Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Sun, 11 May 2008 18:29:44 -0500 Subject: Making ready for RC1 release --- activerecord/lib/active_record/version.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'activerecord/lib') diff --git a/activerecord/lib/active_record/version.rb b/activerecord/lib/active_record/version.rb index a8ee7dbeb9..1463e84764 100644 --- a/activerecord/lib/active_record/version.rb +++ b/activerecord/lib/active_record/version.rb @@ -2,7 +2,7 @@ module ActiveRecord module VERSION #:nodoc: MAJOR = 2 MINOR = 0 - TINY = 2 + TINY = 991 STRING = [MAJOR, MINOR, TINY].join('.') end -- cgit v1.2.3 From 00640de861797b258d2dd955b861bcb021d4a3e1 Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Sun, 11 May 2008 18:34:05 -0500 Subject: Updated copyright years --- activerecord/lib/active_record.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'activerecord/lib') diff --git a/activerecord/lib/active_record.rb b/activerecord/lib/active_record.rb index 8b274120df..d4f7170305 100755 --- a/activerecord/lib/active_record.rb +++ b/activerecord/lib/active_record.rb @@ -1,5 +1,5 @@ #-- -# Copyright (c) 2004-2007 David Heinemeier Hansson +# Copyright (c) 2004-2008 David Heinemeier Hansson # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the -- cgit v1.2.3 From d2212c1601dcd67e72e9d52f98347d3285fd7134 Mon Sep 17 00:00:00 2001 From: Frederick Cheung Date: Mon, 12 May 2008 00:29:16 +0100 Subject: Remove AR::Base#attributes argument. [#52 state:resolved] Signed-off-by: Pratik Naik --- activerecord/lib/active_record/base.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'activerecord/lib') diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index 7999eec55d..392d187092 100755 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -2342,7 +2342,7 @@ 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(options = nil) + def attributes self.attribute_names.inject({}) do |attrs, name| attrs[name] = read_attribute(name) attrs -- cgit v1.2.3 From 654e77597ba1e5b64a2be2e5e21cd542aafcfbb0 Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Mon, 12 May 2008 22:01:58 +0200 Subject: minor details revised in attribute_methods.rb docs --- .../lib/active_record/attribute_methods.rb | 42 ++++++++++++---------- 1 file changed, 24 insertions(+), 18 deletions(-) (limited to 'activerecord/lib') diff --git a/activerecord/lib/active_record/attribute_methods.rb b/activerecord/lib/active_record/attribute_methods.rb index ac40e4f987..c2604894a8 100644 --- a/activerecord/lib/active_record/attribute_methods.rb +++ b/activerecord/lib/active_record/attribute_methods.rb @@ -16,16 +16,20 @@ module ActiveRecord # Declare and check for suffixed attribute methods. module ClassMethods - # Declare a method available for all attributes with the given suffix. - # Uses method_missing and respond_to? to rewrite the method + # Declares a method available for all attributes with the given suffix. + # Uses +method_missing+ and respond_to? to rewrite the method + # # #{attr}#{suffix}(*args, &block) + # # to + # # attribute#{suffix}(#{attr}, *args, &block) # - # An attribute#{suffix} instance method must exist and accept at least - # the attr argument. + # An attribute#{suffix} instance method must exist and accept at least + # the +attr+ argument. # # For example: + # # class Person < ActiveRecord::Base # attribute_method_suffix '_changed?' # @@ -60,8 +64,8 @@ module ActiveRecord !generated_methods.empty? end - # generates all the attribute related methods for columns in the database - # accessors, mutators and query methods + # Generates all the attribute related methods for columns in the database + # accessors, mutators and query methods. def define_attribute_methods return if generated_methods? columns_hash.each do |name, column| @@ -89,8 +93,9 @@ module ActiveRecord end end - # Check to see if the method is defined in the model or any of its subclasses that also derive from ActiveRecord. - # Raise DangerousAttributeError if the method is defined by ActiveRecord though. + # Checks whether the method is defined in the model or any of its subclasses + # that also derive from ActiveRecord. Raises DangerousAttributeError if the + # method is defined by Active Record though. def instance_method_already_implemented?(method_name) method_name = method_name.to_s return true if method_name =~ /^id(=$|\?$|$)/ @@ -104,19 +109,19 @@ module ActiveRecord # +cache_attributes+ allows you to declare which converted attribute values should # be cached. Usually caching only pays off for attributes with expensive conversion - # methods, like time related columns (e.g. created_at, updated_at). + # methods, like time related columns (e.g. +created_at+, +updated_at+). def cache_attributes(*attribute_names) attribute_names.each {|attr| cached_attributes << attr.to_s} end - # returns the attributes which are cached. - # By default time related columns with datatype :datetime, :timestamp, :time, :date are cached + # Returns the attributes which are cached. By default time related columns + # with datatype :datetime, :timestamp, :time, :date are cached. def cached_attributes @cached_attributes ||= columns.select{|c| attribute_types_cached_by_default.include?(c.type)}.map(&:name).to_set end - # returns true if the provided attribute is being cached + # Returns +true+ if the provided attribute is being cached. def cache_attribute?(attr_name) cached_attributes.include?(attr_name) end @@ -212,14 +217,14 @@ module ActiveRecord end # ClassMethods - # Allows access to the object attributes, which are held in the @attributes hash, as though they + # Allows access to the object attributes, which are held in the @attributes hash, as though they # were first-class methods. So a Person class with a name attribute can use Person#name and # Person#name= and never directly use the attributes hash -- except for multiple assigns with # ActiveRecord#attributes=. A Milestone class can also ask Milestone#completed? to test that - # the completed attribute is not nil or 0. + # the completed attribute is not +nil+ or 0. # # It's also possible to instantiate related objects, so a Client class belonging to the clients - # table with a master_id foreign key can instantiate master through Client#master. + # table with a +master_id+ foreign key can instantiate master through Client#master. def method_missing(method_id, *args, &block) method_name = method_id.to_s @@ -290,7 +295,7 @@ module ActiveRecord # Updates the attribute identified by attr_name with the specified +value+. Empty strings for fixnum and float - # columns are turned into nil. + # columns are turned into +nil+. def write_attribute(attr_name, value) attr_name = attr_name.to_s @attributes_cache.delete(attr_name) @@ -321,8 +326,9 @@ module ActiveRecord end end - # A Person object with a name attribute can ask person.respond_to?("name"), person.respond_to?("name="), and - # person.respond_to?("name?") which will all return true. + # A Person object with a name attribute can ask person.respond_to?("name"), + # person.respond_to?("name="), and person.respond_to?("name?") + # which will all return +true+. alias :respond_to_without_attributes? :respond_to? def respond_to?(method, include_priv = false) method_name = method.to_s -- cgit v1.2.3 From 593e21d6aedcc05d744be4996bd7180edce57efe Mon Sep 17 00:00:00 2001 From: Xavier Noria Date: Tue, 13 May 2008 00:46:57 +0200 Subject: Dirty attributes aren't cleared if save fails. [#174 state:resolved] Signed-off-by: Jeremy Kemper --- activerecord/lib/active_record/dirty.rb | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'activerecord/lib') diff --git a/activerecord/lib/active_record/dirty.rb b/activerecord/lib/active_record/dirty.rb index c6d89e3a05..6034963811 100644 --- a/activerecord/lib/active_record/dirty.rb +++ b/activerecord/lib/active_record/dirty.rb @@ -69,19 +69,19 @@ module ActiveRecord changed.inject({}) { |h, attr| h[attr] = attribute_change(attr); h } end - - # Clear changed attributes after they are saved. + # Attempts to +save+ the record and clears changed attributes if successful. def save_with_dirty(*args) #:nodoc: - save_without_dirty(*args) - ensure - changed_attributes.clear + if status = save_without_dirty(*args) + changed_attributes.clear + end + status end - # Clear changed attributes after they are saved. + # Attempts to save! the record and clears changed attributes if successful. def save_with_dirty!(*args) #:nodoc: - save_without_dirty!(*args) - ensure + status = save_without_dirty!(*args) changed_attributes.clear + status end private -- cgit v1.2.3 From bca8751e40a5594c4de2ca58e089b8d98e44632b Mon Sep 17 00:00:00 2001 From: Rodrigo Kochenburger Date: Fri, 11 Apr 2008 12:35:09 -0300 Subject: Add ActiveRecord option to store the full class name on STI's type column, allowing one to have STI subclasses in different namespaces [#114] Signed-off-by: rick --- activerecord/lib/active_record/base.rb | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'activerecord/lib') diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index 392d187092..ac1a35dc91 100755 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -439,6 +439,10 @@ module ActiveRecord #:nodoc: cattr_accessor :schema_format , :instance_writer => false @@schema_format = :ruby + # Determine whether to store the full constant name including namespace when using STI + superclass_delegating_accessor :store_full_sti_class + self.store_full_sti_class = false + class << self # Class methods # Find operates with four different retrieval approaches: # @@ -1557,8 +1561,8 @@ module ActiveRecord #:nodoc: def type_condition quoted_inheritance_column = connection.quote_column_name(inheritance_column) - type_condition = subclasses.inject("#{quoted_table_name}.#{quoted_inheritance_column} = '#{name.demodulize}' ") do |condition, subclass| - condition << "OR #{quoted_table_name}.#{quoted_inheritance_column} = '#{subclass.name.demodulize}' " + type_condition = subclasses.inject("#{quoted_table_name}.#{quoted_inheritance_column} = '#{store_full_sti_class ? name : name.demodulize}' ") do |condition, subclass| + condition << "OR #{quoted_table_name}.#{quoted_inheritance_column} = '#{store_full_sti_class ? subclass.name : subclass.name.demodulize}' " end " (#{type_condition}) " @@ -2492,7 +2496,7 @@ module ActiveRecord #:nodoc: # Message class in that example. def ensure_proper_type unless self.class.descends_from_active_record? - write_attribute(self.class.inheritance_column, Inflector.demodulize(self.class.name)) + write_attribute(self.class.inheritance_column, store_full_sti_class ? self.class.name : Inflector.demodulize(self.class.name)) end end -- cgit v1.2.3 From 3b0e1d90938e3d4c98830e037b3da15b3f736f7f Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Wed, 14 May 2008 14:09:49 -0500 Subject: Prefer string core_ext inflector methods over directly accessing Inflector. --- activerecord/lib/active_record/base.rb | 44 +++++++++++++++--------------- activerecord/lib/active_record/fixtures.rb | 14 +++++----- 2 files changed, 29 insertions(+), 29 deletions(-) (limited to 'activerecord/lib') diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index ac1a35dc91..5351f55200 100755 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -438,11 +438,11 @@ module ActiveRecord #:nodoc: # adapters for, e.g., your development and test environments. cattr_accessor :schema_format , :instance_writer => false @@schema_format = :ruby - + # Determine whether to store the full constant name including namespace when using STI superclass_delegating_accessor :store_full_sti_class self.store_full_sti_class = false - + class << self # Class methods # Find operates with four different retrieval approaches: # @@ -526,7 +526,7 @@ module ActiveRecord #:nodoc: else find_from_ids(args, options) end end - + # This is an alias for find(:first). You can pass in all the same arguments to this method as you can # to find(:first) def first(*args) @@ -538,13 +538,13 @@ module ActiveRecord #:nodoc: def last(*args) find(:last, *args) end - + # This is an alias for find(:all). You can pass in all the same arguments to this method as you can # to find(:all) def all(*args) find(:all, *args) end - + # # Executes a custom sql query against your database and returns all the results. The results will # be returned as an array with columns requested encapsulated as attributes of the model you call @@ -591,10 +591,10 @@ module ActiveRecord #:nodoc: def exists?(id_or_conditions) connection.select_all( construct_finder_sql( - :select => "#{quoted_table_name}.#{primary_key}", - :conditions => expand_id_conditions(id_or_conditions), + :select => "#{quoted_table_name}.#{primary_key}", + :conditions => expand_id_conditions(id_or_conditions), :limit => 1 - ), + ), "#{name} Exists" ).size > 0 end @@ -620,7 +620,7 @@ module ActiveRecord #:nodoc: # # Creating an Array of new objects using a block, where the block is executed for each object: # User.create([{ :first_name => 'Jamie' }, { :first_name => 'Jeremy' }]) do |u| # u.is_admin = false - # end + # end def create(attributes = nil, &block) if attributes.is_a?(Array) attributes.collect { |attr| create(attr, &block) } @@ -1027,9 +1027,9 @@ module ActiveRecord #:nodoc: key = 'id' case primary_key_prefix_type when :table_name - key = Inflector.foreign_key(base_name, false) + key = base_name.to_s.foreign_key(false) when :table_name_with_underscore - key = Inflector.foreign_key(base_name) + key = base_name.to_s.foreign_key end key end @@ -1302,7 +1302,7 @@ module ActiveRecord #:nodoc: scoped_order = reverse_sql_order(scope(:find, :order)) scoped_methods.select { |s| s[:find].update(:order => scoped_order) } end - + find_initial(options.merge({ :order => order })) end @@ -1312,12 +1312,12 @@ module ActiveRecord #:nodoc: s.gsub!(/\s(asc|ASC)$/, ' DESC') elsif s.match(/\s(desc|DESC)$/) s.gsub!(/\s(desc|DESC)$/, ' ASC') - elsif !s.match(/\s(asc|ASC|desc|DESC)$/) + elsif !s.match(/\s(asc|ASC|desc|DESC)$/) s.concat(' DESC') end }.join(',') end - + def find_every(options) include_associations = merge_includes(scope(:find, :include), options[:include]) @@ -1570,8 +1570,8 @@ module ActiveRecord #:nodoc: # Guesses the table name, but does not decorate it with prefix and suffix information. def undecorated_table_name(class_name = base_class.name) - table_name = Inflector.underscore(Inflector.demodulize(class_name)) - table_name = Inflector.pluralize(table_name) if pluralize_table_names + table_name = class_name.to_s.demodulize.underscore + table_name = table_name.pluralize if pluralize_table_names table_name end @@ -1620,7 +1620,7 @@ module ActiveRecord #:nodoc: self.class_eval %{ def self.#{method_id}(*args) guard_protected_attributes = false - + if args[0].is_a?(Hash) guard_protected_attributes = true attributes = args[0].with_indifferent_access @@ -1633,7 +1633,7 @@ module ActiveRecord #:nodoc: set_readonly_option!(options) record = find_initial(options) - + if record.nil? record = self.new { |r| r.send(:attributes=, attributes, guard_protected_attributes) } #{'yield(record) if block_given?'} @@ -2133,14 +2133,14 @@ module ActiveRecord #:nodoc: # 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 end - + # Returns a cache key that can be used to identify this record. Examples: # # Product.new.cache_key # => "products/new" # Product.find(5).cache_key # => "products/5" (updated_at not available) # Person.find(5).cache_key # => "people/5-20071224150000" (updated_at available) def cache_key - case + case when new_record? "#{self.class.name.tableize}/new" when self[:updated_at] @@ -2174,7 +2174,7 @@ module ActiveRecord #:nodoc: # Note: If your model specifies any validations then the method declaration dynamically # changes to: # save(perform_validation=true) - # Calling save(false) saves the model without running validations. + # Calling save(false) saves the model without running validations. # See ActiveRecord::Validations for more information. def save create_or_update @@ -2496,7 +2496,7 @@ module ActiveRecord #:nodoc: # Message class in that example. def ensure_proper_type unless self.class.descends_from_active_record? - write_attribute(self.class.inheritance_column, store_full_sti_class ? self.class.name : Inflector.demodulize(self.class.name)) + write_attribute(self.class.inheritance_column, store_full_sti_class ? self.class.name : self.class.name.demodulize) end end diff --git a/activerecord/lib/active_record/fixtures.rb b/activerecord/lib/active_record/fixtures.rb index 9367ea523d..ac06cdbe43 100755 --- a/activerecord/lib/active_record/fixtures.rb +++ b/activerecord/lib/active_record/fixtures.rb @@ -197,20 +197,20 @@ end # class FooTest < ActiveSupport::TestCase # self.use_transactional_fixtures = true # self.use_instantiated_fixtures = false -# +# # fixtures :foos -# +# # def test_godzilla # assert !Foo.find(:all).empty? # Foo.destroy_all # assert Foo.find(:all).empty? # end -# +# # def test_godzilla_aftermath # assert !Foo.find(:all).empty? # end # end -# +# # If you preload your test database with all fixture data (probably in the Rakefile task) and use transactional fixtures, # then you may omit all fixtures declarations in your test cases since all the data's already there and every case rolls back its changes. # @@ -730,7 +730,7 @@ class Fixtures < (RUBY_VERSION < '1.9' ? YAML::Omap : Hash) reader.each do |row| data = {} row.each_with_index { |cell, j| data[header[j].to_s.strip] = cell.to_s.strip } - self["#{Inflector::underscore(@class_name)}_#{i+=1}"] = Fixture.new(data, model_class) + self["#{@class_name.to_s.underscore}_#{i+=1}"] = Fixture.new(data, model_class) end end @@ -854,14 +854,14 @@ module Test #:nodoc: 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 end - + def require_fixture_classes(table_names = nil) (table_names || fixture_table_names).each do |table_name| file_name = table_name.to_s -- cgit v1.2.3 From b28b54cab090bed8f099ef375b419a8f92390dd4 Mon Sep 17 00:00:00 2001 From: John Devine Date: Sun, 4 May 2008 14:08:19 -0500 Subject: Make sure needed table joins are included :select option. [#110 state:resolved] Signed-off-by: Pratik Naik --- activerecord/lib/active_record/associations.rb | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) (limited to 'activerecord/lib') diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb index fb5f1f8a8c..7862f8ad9d 100644 --- a/activerecord/lib/active_record/associations.rb +++ b/activerecord/lib/active_record/associations.rb @@ -1500,6 +1500,12 @@ module ActiveRecord order.scan(/([\.\w]+).?\./).flatten end + def selects_tables(options) + select = options[:select] + return [] unless select && select.is_a?(String) + select.scan(/"?([\.\w]+)"?.?\./).flatten + end + # Checks if the conditions reference a table other than the current model table def include_eager_conditions?(options,tables = nil) tables = conditions_tables(options) @@ -1518,8 +1524,16 @@ module ActiveRecord end end + def include_eager_select?(options) + selects = selects_tables(options) + return false unless selects.any? + selects.any? do |select| + select != table_name + end + end + def references_eager_loaded_tables?(options) - include_eager_order?(options) || include_eager_conditions?(options) + include_eager_order?(options) || include_eager_conditions?(options) || include_eager_select?(options) end def using_limitable_reflections?(reflections) -- cgit v1.2.3 From 802034ff5f1c3e3b576b664d5660e76c8f44909d Mon Sep 17 00:00:00 2001 From: Pratik Naik Date: Thu, 15 May 2008 13:41:54 +0100 Subject: DRY associations code and improve eager loading tests. --- activerecord/lib/active_record/associations.rb | 25 +++++-------------------- 1 file changed, 5 insertions(+), 20 deletions(-) (limited to 'activerecord/lib') diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb index 7862f8ad9d..c17e35f5e0 100644 --- a/activerecord/lib/active_record/associations.rb +++ b/activerecord/lib/active_record/associations.rb @@ -1451,9 +1451,6 @@ module ActiveRecord join_dependency.joins_for_table_name(table) }.flatten.compact.uniq - - - is_distinct = !options[:joins].blank? || include_eager_conditions?(options, tables_from_conditions) || include_eager_order?(options, tables_from_order) sql = "SELECT " if is_distinct @@ -1507,29 +1504,17 @@ module ActiveRecord end # Checks if the conditions reference a table other than the current model table - def include_eager_conditions?(options,tables = nil) - tables = conditions_tables(options) - return false unless tables.any? - tables.any? do |condition_table_name| - condition_table_name != table_name - end + def include_eager_conditions?(options, tables = nil) + ((tables || conditions_tables(options)) - [table_name]).any? end # Checks if the query order references a table other than the current model's table. - def include_eager_order?(options,tables = nil) - tables = order_tables(options) - return false unless tables.any? - tables.any? do |order_table_name| - order_table_name != table_name - end + def include_eager_order?(options, tables = nil) + ((tables || order_tables(options)) - [table_name]).any? end def include_eager_select?(options) - selects = selects_tables(options) - return false unless selects.any? - selects.any? do |select| - select != table_name - end + (selects_tables(options) - [table_name]).any? end def references_eager_loaded_tables?(options) -- cgit v1.2.3