diff options
Diffstat (limited to 'activerecord')
-rwxr-xr-x | activerecord/Rakefile | 4 | ||||
-rw-r--r-- | activerecord/lib/active_record/fixtures.rb | 4 | ||||
-rw-r--r-- | activerecord/lib/active_record/persistence.rb | 6 | ||||
-rw-r--r-- | activerecord/lib/active_record/railties/databases.rake | 2 | ||||
-rw-r--r-- | activerecord/lib/active_record/relation.rb | 41 | ||||
-rw-r--r-- | activerecord/test/cases/associations/eager_test.rb | 40 | ||||
-rw-r--r-- | activerecord/test/cases/associations/has_many_through_associations_test.rb | 42 | ||||
-rw-r--r-- | activerecord/test/fixtures/parrots.yml | 2 | ||||
-rw-r--r-- | activerecord/test/models/developer.rb | 35 |
9 files changed, 152 insertions, 24 deletions
diff --git a/activerecord/Rakefile b/activerecord/Rakefile index e414c4fb1c..346c7e8142 100755 --- a/activerecord/Rakefile +++ b/activerecord/Rakefile @@ -1,7 +1,7 @@ #!/usr/bin/env rake require 'rake/testtask' require 'rake/packagetask' -require 'rake/gempackagetask' +require 'rubygems/package_task' require File.expand_path(File.dirname(__FILE__)) + "/test/config" @@ -171,7 +171,7 @@ task :rebuild_frontbase_databases => 'frontbase:rebuild_databases' spec = eval(File.read('activerecord.gemspec')) -Rake::GemPackageTask.new(spec) do |p| +Gem::PackageTask.new(spec) do |p| p.gem_spec = spec end diff --git a/activerecord/lib/active_record/fixtures.rb b/activerecord/lib/active_record/fixtures.rb index 49df63d585..1f31722a7c 100644 --- a/activerecord/lib/active_record/fixtures.rb +++ b/activerecord/lib/active_record/fixtures.rb @@ -385,11 +385,11 @@ class FixturesFileNotFound < StandardError; end # # first: # name: Smurf -# <<: *DEFAULTS +# *DEFAULTS # # second: # name: Fraggle -# <<: *DEFAULTS +# *DEFAULTS # # Any fixture labeled "DEFAULTS" is safely ignored. diff --git a/activerecord/lib/active_record/persistence.rb b/activerecord/lib/active_record/persistence.rb index b9041f44d8..e84a479a13 100644 --- a/activerecord/lib/active_record/persistence.rb +++ b/activerecord/lib/active_record/persistence.rb @@ -33,7 +33,11 @@ module ActiveRecord # +save+ returns +false+. See ActiveRecord::Callbacks for further # details. def save(*) - create_or_update + begin + create_or_update + rescue ActiveRecord::RecordInvalid + false + end end # Saves the model. diff --git a/activerecord/lib/active_record/railties/databases.rake b/activerecord/lib/active_record/railties/databases.rake index 089bbed08a..2c7298e220 100644 --- a/activerecord/lib/active_record/railties/databases.rake +++ b/activerecord/lib/active_record/railties/databases.rake @@ -27,7 +27,7 @@ db_namespace = namespace :db do # # development: # database: blog_development - # <<: *defaults + # *defaults next unless config['database'] # Only connect to local databases local_database?(config) { create_database(config) } diff --git a/activerecord/lib/active_record/relation.rb b/activerecord/lib/active_record/relation.rb index ae9afad48a..a3f4a6fe94 100644 --- a/activerecord/lib/active_record/relation.rb +++ b/activerecord/lib/active_record/relation.rb @@ -102,24 +102,30 @@ module ActiveRecord def to_a return @records if loaded? - @records = if @readonly_value.nil? && !@klass.locking_enabled? - eager_loading? ? find_with_associations : @klass.find_by_sql(arel.to_sql, @bind_values) - else - IdentityMap.without do + default_scoped = with_default_scope + + if default_scoped.equal?(self) + @records = if @readonly_value.nil? && !@klass.locking_enabled? eager_loading? ? find_with_associations : @klass.find_by_sql(arel.to_sql, @bind_values) + else + IdentityMap.without do + eager_loading? ? find_with_associations : @klass.find_by_sql(arel.to_sql, @bind_values) + end end - end - preload = @preload_values - preload += @includes_values unless eager_loading? - preload.each do |associations| - ActiveRecord::Associations::Preloader.new(@records, associations).run - end + preload = @preload_values + preload += @includes_values unless eager_loading? + preload.each do |associations| + ActiveRecord::Associations::Preloader.new(@records, associations).run + end - # @readonly_value is true only if set explicitly. @implicit_readonly is true if there - # are JOINS and no explicit SELECT. - readonly = @readonly_value.nil? ? @implicit_readonly : @readonly_value - @records.each { |record| record.readonly! } if readonly + # @readonly_value is true only if set explicitly. @implicit_readonly is true if there + # are JOINS and no explicit SELECT. + readonly = @readonly_value.nil? ? @implicit_readonly : @readonly_value + @records.each { |record| record.readonly! } if readonly + else + @records = default_scoped.to_a + end @loaded = true @records @@ -418,9 +424,10 @@ module ActiveRecord end def with_default_scope #:nodoc: - if default_scoped? - default_scope = @klass.send(:build_default_scope) - default_scope ? default_scope.merge(self) : self + if default_scoped? && default_scope = @klass.send(:build_default_scope) + default_scope = default_scope.merge(self) + default_scope.default_scoped = false + default_scope else self end diff --git a/activerecord/test/cases/associations/eager_test.rb b/activerecord/test/cases/associations/eager_test.rb index ea186be9dd..5028cee32d 100644 --- a/activerecord/test/cases/associations/eager_test.rb +++ b/activerecord/test/cases/associations/eager_test.rb @@ -681,6 +681,46 @@ class EagerAssociationTest < ActiveRecord::TestCase } end + def test_eager_with_default_scope + developer = EagerDeveloperWithDefaultScope.where(:name => 'David').first + projects = Project.order(:id).all + assert_no_queries do + assert_equal(projects, developer.projects) + end + end + + def test_eager_with_default_scope_as_class_method + developer = EagerDeveloperWithClassMethodDefaultScope.where(:name => 'David').first + projects = Project.order(:id).all + assert_no_queries do + assert_equal(projects, developer.projects) + end + end + + def test_eager_with_default_scope_as_lambda + developer = EagerDeveloperWithLambdaDefaultScope.where(:name => 'David').first + projects = Project.order(:id).all + assert_no_queries do + assert_equal(projects, developer.projects) + end + end + + def test_eager_with_default_scope_as_block + developer = EagerDeveloperWithBlockDefaultScope.where(:name => 'David').first + projects = Project.order(:id).all + assert_no_queries do + assert_equal(projects, developer.projects) + end + end + + def test_eager_with_default_scope_as_callable + developer = EagerDeveloperWithCallableDefaultScope.where(:name => 'David').first + projects = Project.order(:id).all + assert_no_queries do + assert_equal(projects, developer.projects) + end + end + def find_all_ordered(className, include=nil) className.find(:all, :order=>"#{className.table_name}.#{className.primary_key}", :include=>include) end diff --git a/activerecord/test/cases/associations/has_many_through_associations_test.rb b/activerecord/test/cases/associations/has_many_through_associations_test.rb index 89117593fd..877148bd5e 100644 --- a/activerecord/test/cases/associations/has_many_through_associations_test.rb +++ b/activerecord/test/cases/associations/has_many_through_associations_test.rb @@ -766,4 +766,46 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase assert_equal [category.name], post.named_category_ids # checks when target loaded assert_equal [category.name], post.reload.named_category_ids # checks when target no loaded end + + def test_create_should_not_raise_exception_when_join_record_has_errors + repair_validations(Categorization) do + Categorization.validate { |r| r.errors[:base] << 'Invalid Categorization' } + Category.create(:name => 'Fishing', :authors => [Author.first]) + end + end + + def test_save_should_not_raise_exception_when_join_record_has_errors + repair_validations(Categorization) do + Categorization.validate { |r| r.errors[:base] << 'Invalid Categorization' } + c = Category.create(:name => 'Fishing', :authors => [Author.first]) + c.save + end + end + + def test_create_bang_should_raise_exception_when_join_record_has_errors + repair_validations(Categorization) do + Categorization.validate { |r| r.errors[:base] << 'Invalid Categorization' } + assert_raises(ActiveRecord::RecordInvalid) do + Category.create!(:name => 'Fishing', :authors => [Author.first]) + end + end + end + + def test_save_bang_should_raise_exception_when_join_record_has_errors + repair_validations(Categorization) do + Categorization.validate { |r| r.errors[:base] << 'Invalid Categorization' } + c = Category.new(:name => 'Fishing', :authors => [Author.first]) + assert_raises(ActiveRecord::RecordInvalid) do + c.save! + end + end + end + + def test_create_bang_returns_falsy_when_join_record_has_errors + repair_validations(Categorization) do + Categorization.validate { |r| r.errors[:base] << 'Invalid Categorization' } + c = Category.new(:name => 'Fishing', :authors => [Author.first]) + assert !c.save + end + end end diff --git a/activerecord/test/fixtures/parrots.yml b/activerecord/test/fixtures/parrots.yml index 8b73b8cdf6..8425ef98e0 100644 --- a/activerecord/test/fixtures/parrots.yml +++ b/activerecord/test/fixtures/parrots.yml @@ -24,4 +24,4 @@ DEFAULTS: &DEFAULTS parrot_sti_class: LiveParrot davey: - <<: *DEFAULTS + *DEFAULTS diff --git a/activerecord/test/models/developer.rb b/activerecord/test/models/developer.rb index 152f804e16..a2aa8ae664 100644 --- a/activerecord/test/models/developer.rb +++ b/activerecord/test/models/developer.rb @@ -165,4 +165,39 @@ class ModuleIncludedPoorDeveloperCalledJamis < DeveloperCalledJamis include SalaryDefaultScope end +class EagerDeveloperWithDefaultScope < ActiveRecord::Base + self.table_name = 'developers' + has_and_belongs_to_many :projects, :foreign_key => 'developer_id', :join_table => 'developers_projects', :order => 'projects.id' + + default_scope includes(:projects) +end + +class EagerDeveloperWithClassMethodDefaultScope < ActiveRecord::Base + self.table_name = 'developers' + has_and_belongs_to_many :projects, :foreign_key => 'developer_id', :join_table => 'developers_projects', :order => 'projects.id' + + def self.default_scope + includes(:projects) + end +end + +class EagerDeveloperWithLambdaDefaultScope < ActiveRecord::Base + self.table_name = 'developers' + has_and_belongs_to_many :projects, :foreign_key => 'developer_id', :join_table => 'developers_projects', :order => 'projects.id' + + default_scope lambda { includes(:projects) } +end + +class EagerDeveloperWithBlockDefaultScope < ActiveRecord::Base + self.table_name = 'developers' + has_and_belongs_to_many :projects, :foreign_key => 'developer_id', :join_table => 'developers_projects', :order => 'projects.id' + default_scope { includes(:projects) } +end + +class EagerDeveloperWithCallableDefaultScope < ActiveRecord::Base + self.table_name = 'developers' + has_and_belongs_to_many :projects, :foreign_key => 'developer_id', :join_table => 'developers_projects', :order => 'projects.id' + + default_scope OpenStruct.new(:call => includes(:projects)) +end |