diff options
Diffstat (limited to 'activerecord')
12 files changed, 67 insertions, 27 deletions
diff --git a/activerecord/activerecord.gemspec b/activerecord/activerecord.gemspec index 53791d96ef..31ddb01123 100644 --- a/activerecord/activerecord.gemspec +++ b/activerecord/activerecord.gemspec @@ -1,4 +1,4 @@ -version = File.read(File.expand_path("../../RAILS_VERSION", __FILE__)).strip +version = File.read(File.expand_path('../../RAILS_VERSION', __FILE__)).strip Gem::Specification.new do |s| s.platform = Gem::Platform::RUBY @@ -8,21 +8,22 @@ Gem::Specification.new do |s| 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.9.3' - s.license = 'MIT' - s.author = 'David Heinemeier Hansson' - s.email = 'david@loudthinking.com' - s.homepage = 'http://www.rubyonrails.org' + s.license = 'MIT' + + s.author = 'David Heinemeier Hansson' + s.email = 'david@loudthinking.com' + s.homepage = 'http://www.rubyonrails.org' s.files = Dir['CHANGELOG.md', 'MIT-LICENSE', 'README.rdoc', 'examples/**/*', 'lib/**/*'] s.require_path = 'lib' - s.extra_rdoc_files = %w( README.rdoc ) + s.extra_rdoc_files = %w(README.rdoc) s.rdoc_options.concat ['--main', 'README.rdoc'] - s.add_dependency('activesupport', version) - s.add_dependency('activemodel', version) - s.add_dependency('arel', '~> 3.0.2') + s.add_dependency 'activesupport', version + s.add_dependency 'activemodel', version - s.add_dependency('activerecord-deprecated_finders', '0.0.1') + s.add_dependency 'arel', '~> 3.0.2' + s.add_dependency 'activerecord-deprecated_finders', '0.0.1' end diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb index 5dd833e5a6..5949269f2a 100644 --- a/activerecord/lib/active_record/associations.rb +++ b/activerecord/lib/active_record/associations.rb @@ -1,6 +1,9 @@ require 'active_support/core_ext/enumerable' require 'active_support/core_ext/string/conversions' require 'active_support/core_ext/module/remove_method' +require 'active_support/dependencies/autoload' +require 'active_support/concern' +require 'active_record/errors' module ActiveRecord class InverseOfAssociationNotFoundError < ActiveRecordError #:nodoc: diff --git a/activerecord/lib/active_record/associations/builder/collection_association.rb b/activerecord/lib/active_record/associations/builder/collection_association.rb index 1b382f7285..fcdfc1e150 100644 --- a/activerecord/lib/active_record/associations/builder/collection_association.rb +++ b/activerecord/lib/active_record/associations/builder/collection_association.rb @@ -1,5 +1,8 @@ +require 'active_record/associations' + module ActiveRecord::Associations::Builder class CollectionAssociation < Association #:nodoc: + CALLBACKS = [:before_add, :after_add, :before_remove, :after_remove] def valid_options diff --git a/activerecord/lib/active_record/associations/collection_association.rb b/activerecord/lib/active_record/associations/collection_association.rb index 54215cf88d..862ff201de 100644 --- a/activerecord/lib/active_record/associations/collection_association.rb +++ b/activerecord/lib/active_record/associations/collection_association.rb @@ -174,8 +174,6 @@ module ActiveRecord # association, it will be used for the query. Otherwise, construct options and pass them with # scope to the target class's +count+. def count(column_name = nil, count_options = {}) - return 0 if owner.new_record? - column_name, count_options = nil, column_name if column_name.is_a?(Hash) if options[:counter_sql] || options[:finder_sql] @@ -366,6 +364,16 @@ module ActiveRecord record end + def scope(opts = {}) + scope = super() + scope.none! if opts.fetch(:nullify, true) && null_scope? + scope + end + + def null_scope? + owner.new_record? && !foreign_key_present? + end + private def custom_counter_sql diff --git a/activerecord/lib/active_record/associations/collection_proxy.rb b/activerecord/lib/active_record/associations/collection_proxy.rb index e73f940334..1b746b46b7 100644 --- a/activerecord/lib/active_record/associations/collection_proxy.rb +++ b/activerecord/lib/active_record/associations/collection_proxy.rb @@ -28,10 +28,12 @@ module ActiveRecord # is computed directly through SQL and does not trigger by itself the # instantiation of the actual post records. class CollectionProxy < Relation + delegate *ActiveRecord::Calculations.public_instance_methods, to: :scope + def initialize(association) #:nodoc: @association = association super association.klass, association.klass.arel_table - merge! association.scope + merge! association.scope(nullify: false) end def target diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index eabbd80f66..a694a292fe 100644 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -8,7 +8,6 @@ require 'active_support/core_ext/class/attribute_accessors' require 'active_support/core_ext/class/delegating_attributes' require 'active_support/core_ext/array/extract_options' 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/kernel/singleton_class' diff --git a/activerecord/lib/active_record/migration.rb b/activerecord/lib/active_record/migration.rb index c3b9a0f9b7..22347fcaef 100644 --- a/activerecord/lib/active_record/migration.rb +++ b/activerecord/lib/active_record/migration.rb @@ -642,7 +642,11 @@ module ActiveRecord def proper_table_name(name) # Use the Active Record objects own table_name, or pre/suffix from ActiveRecord::Base if name is a symbol/string - name.table_name rescue "#{ActiveRecord::Base.table_name_prefix}#{name}#{ActiveRecord::Base.table_name_suffix}" + if name.respond_to? :table_name + name.table_name + else + "#{ActiveRecord::Base.table_name_prefix}#{name}#{ActiveRecord::Base.table_name_suffix}" + end end def migrations_paths diff --git a/activerecord/lib/active_record/null_relation.rb b/activerecord/lib/active_record/null_relation.rb index 4c1c91e3df..711fc8b883 100644 --- a/activerecord/lib/active_record/null_relation.rb +++ b/activerecord/lib/active_record/null_relation.rb @@ -46,7 +46,11 @@ module ActiveRecord {} end - def count + def count(*) + 0 + end + + def sum(*) 0 end diff --git a/activerecord/lib/active_record/relation/finder_methods.rb b/activerecord/lib/active_record/relation/finder_methods.rb index 99c2f45bc8..af67b2ba6c 100644 --- a/activerecord/lib/active_record/relation/finder_methods.rb +++ b/activerecord/lib/active_record/relation/finder_methods.rb @@ -1,5 +1,3 @@ -require 'active_support/core_ext/hash/indifferent_access' - module ActiveRecord module FinderMethods # Find by id - This can either be a specific id (1), a list of ids (1, 5, 6), or an array of ids ([5, 6, 10]). @@ -225,7 +223,7 @@ module ActiveRecord def construct_limited_ids_condition(relation) orders = relation.order_values.map { |val| val.presence }.compact - values = @klass.connection.distinct("#{@klass.connection.quote_table_name table_name}.#{primary_key}", orders) + values = @klass.connection.distinct("#{quoted_table_name}.#{primary_key}", orders) relation = relation.dup @@ -234,8 +232,6 @@ module ActiveRecord end def find_with_ids(*ids) - return to_a.find { |*block_args| yield(*block_args) } if block_given? - expects_array = ids.first.kind_of?(Array) return ids.first if expects_array && ids.first.empty? diff --git a/activerecord/lib/active_record/relation/query_methods.rb b/activerecord/lib/active_record/relation/query_methods.rb index 4fdc296c7e..0817bb6d81 100644 --- a/activerecord/lib/active_record/relation/query_methods.rb +++ b/activerecord/lib/active_record/relation/query_methods.rb @@ -218,7 +218,6 @@ module ActiveRecord # Like #order, but modifies relation in place. def order!(*args) args.flatten! - validate_order_args args references = args.reject { |arg| Arel::Node === arg } @@ -245,7 +244,6 @@ module ActiveRecord # Like #reorder, but modifies relation in place. def reorder!(*args) args.flatten! - validate_order_args args self.reordering_value = true @@ -796,7 +794,7 @@ module ActiveRecord def reverse_sql_order(order_query) order_query = ["#{quoted_table_name}.#{quoted_primary_key} ASC"] if order_query.empty? - order_query.map do |o| + order_query.flat_map do |o| case o when Arel::Nodes::Ordering o.reverse @@ -814,7 +812,7 @@ module ActiveRecord else o end - end.flatten + end end def array_of_strings?(o) @@ -825,7 +823,7 @@ module ActiveRecord orders = order_values orders = reverse_sql_order(orders) if reverse_order_value - orders = orders.uniq.reject(&:blank?).map do |order| + orders = orders.uniq.reject(&:blank?).flat_map do |order| case order when Symbol table[order].asc @@ -834,7 +832,7 @@ module ActiveRecord else order end - end.flatten + end arel.order(*orders) unless orders.empty? end diff --git a/activerecord/test/cases/associations/has_many_associations_test.rb b/activerecord/test/cases/associations/has_many_associations_test.rb index 8077222e30..45b0a76f5a 100644 --- a/activerecord/test/cases/associations/has_many_associations_test.rb +++ b/activerecord/test/cases/associations/has_many_associations_test.rb @@ -1656,4 +1656,15 @@ class HasManyAssociationsTest < ActiveRecord::TestCase klass = Class.new(ActiveRecord::Base) assert_deprecated { klass.has_many :foo, :counter_sql => 'lol' } end + + test "has many associations on new records use null relations" do + post = Post.new + + assert_no_queries do + assert_equal [], post.comments + assert_equal [], post.comments.where(body: 'omg') + assert_equal [], post.comments.pluck(:body) + assert_equal 0, post.comments.sum(:id) + end + end end diff --git a/activerecord/test/cases/nested_attributes_test.rb b/activerecord/test/cases/nested_attributes_test.rb index 9674f2ce94..3f08f9ea4d 100644 --- a/activerecord/test/cases/nested_attributes_test.rb +++ b/activerecord/test/cases/nested_attributes_test.rb @@ -185,6 +185,17 @@ class TestNestedAttributesInGeneral < ActiveRecord::TestCase assert_equal "James", mean_pirate.parrot.name assert_equal "blue", mean_pirate.parrot.color end + + def test_accepts_nested_attributes_for_can_be_overridden_in_subclasses + Pirate.accepts_nested_attributes_for(:parrot) + + mean_pirate_class = Class.new(Pirate) do + accepts_nested_attributes_for :parrot + end + mean_pirate = mean_pirate_class.new + mean_pirate.parrot_attributes = { :name => "James" } + assert_equal "James", mean_pirate.parrot.name + end end class TestNestedAttributesOnAHasOneAssociation < ActiveRecord::TestCase |