diff options
19 files changed, 113 insertions, 17 deletions
diff --git a/actionpack/test/controller/url_for_test.rb b/actionpack/test/controller/url_for_test.rb index d2b4952759..a8035e5bd7 100644 --- a/actionpack/test/controller/url_for_test.rb +++ b/actionpack/test/controller/url_for_test.rb @@ -204,9 +204,6 @@ module AbstractController end def test_relative_url_root_is_respected - # ROUTES TODO: Tests should not have to pass :relative_url_root directly. This - # should probably come from routes. - add_host! assert_equal('https://www.basecamphq.com/subdir/c/a/i', W.new.url_for(:controller => 'c', :action => 'a', :id => 'i', :protocol => 'https', :script_name => '/subdir') diff --git a/actionpack/test/dispatch/static_test.rb b/actionpack/test/dispatch/static_test.rb index 5bd1806b21..afdda70748 100644 --- a/actionpack/test/dispatch/static_test.rb +++ b/actionpack/test/dispatch/static_test.rb @@ -136,10 +136,15 @@ module StaticTests def with_static_file(file) path = "#{FIXTURE_LOAD_PATH}/#{public_path}" + file - File.open(path, "wb+") { |f| f.write(file) } + begin + File.open(path, "wb+") { |f| f.write(file) } + rescue Errno::EPROTO + skip "Couldn't create a file #{path}" + end + yield file ensure - File.delete(path) + File.delete(path) if File.exist? path end end diff --git a/activerecord/lib/active_record/autosave_association.rb b/activerecord/lib/active_record/autosave_association.rb index e9622ca0c1..4f58d06f35 100644 --- a/activerecord/lib/active_record/autosave_association.rb +++ b/activerecord/lib/active_record/autosave_association.rb @@ -301,7 +301,7 @@ module ActiveRecord def association_valid?(reflection, record) return true if record.destroyed? || record.marked_for_destruction? - unless valid = record.valid? + unless valid = record.valid?(self.validation_context) if reflection.options[:autosave] record.errors.each do |attribute, message| attribute = "#{reflection.name}.#{attribute}" diff --git a/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb b/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb index cebe741daa..759e162e19 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb @@ -393,7 +393,7 @@ module ActiveRecord synchronize do stale = Time.now - @dead_connection_timeout connections.dup.each do |conn| - if conn.in_use? && stale > conn.last_use && !conn.active? + if conn.in_use? && stale > conn.last_use && !conn.active_threadsafe? remove conn end end diff --git a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb index 3c94bad208..11b28a4858 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb @@ -262,6 +262,12 @@ module ActiveRecord def active? end + # Adapter should redefine this if it needs a threadsafe way to approximate + # if the connection is active + def active_threadsafe? + active? + end + # Disconnects from the database if already connected, and establishes a # new connection with the database. Implementors should call super if they # override the default implementation. diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb index 9618ba4087..36c7462419 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb @@ -586,11 +586,16 @@ module ActiveRecord # Is this connection alive and ready for queries? def active? - @connection.connect_poll != PG::PGRES_POLLING_FAILED + @connection.query 'SELECT 1' + true rescue PGError false end + def active_threadsafe? + @connection.connect_poll != PG::PGRES_POLLING_FAILED + end + # Close then reopen the connection. def reconnect! super diff --git a/activerecord/test/cases/associations/has_many_associations_test.rb b/activerecord/test/cases/associations/has_many_associations_test.rb index a86fb15719..321440cab7 100644 --- a/activerecord/test/cases/associations/has_many_associations_test.rb +++ b/activerecord/test/cases/associations/has_many_associations_test.rb @@ -22,6 +22,8 @@ require 'models/engine' require 'models/categorization' require 'models/minivan' require 'models/speedometer' +require 'models/pirate' +require 'models/ship' class HasManyAssociationsTestForReorderWithJoinDependency < ActiveRecord::TestCase fixtures :authors, :posts, :comments @@ -1830,4 +1832,12 @@ class HasManyAssociationsTest < ActiveRecord::TestCase end end end + + test 'has_many_association passes context validation to validate children' do + pirate = FamousPirate.new + pirate.famous_ships << ship = FamousShip.new + assert_equal true, pirate.valid? + assert_equal false, pirate.valid?(:conference) + assert_equal "can't be blank", ship.errors[:name].first + end end diff --git a/activerecord/test/cases/autosave_association_test.rb b/activerecord/test/cases/autosave_association_test.rb index 7a0c335627..c55dd685a1 100644 --- a/activerecord/test/cases/autosave_association_test.rb +++ b/activerecord/test/cases/autosave_association_test.rb @@ -17,6 +17,8 @@ require 'models/tag' require 'models/tagging' require 'models/treasure' require 'models/eye' +require 'models/electron' +require 'models/molecule' class TestAutosaveAssociationsInGeneral < ActiveRecord::TestCase def test_should_not_add_the_same_callbacks_multiple_times_for_has_one @@ -343,6 +345,33 @@ class TestDefaultAutosaveAssociationOnABelongsToAssociation < ActiveRecord::Test end end +class TestDefaultAutosaveAssociationOnAHasManyAssociationWithAcceptsNestedAttributes < ActiveRecord::TestCase + def test_invalid_adding_with_nested_attributes + molecule = Molecule.new + valid_electron = Electron.new(name: 'electron') + invalid_electron = Electron.new + + molecule.electrons = [valid_electron, invalid_electron] + molecule.save + + assert_not invalid_electron.valid? + assert valid_electron.valid? + assert_not molecule.persisted?, 'Molecule should not be persisted when its electrons are invalid' + end + + def test_valid_adding_with_nested_attributes + molecule = Molecule.new + valid_electron = Electron.new(name: 'electron') + + molecule.electrons = [valid_electron] + molecule.save + + assert valid_electron.valid? + assert molecule.persisted? + assert_equal 1, molecule.electrons.count + end +end + class TestDefaultAutosaveAssociationOnAHasManyAssociation < ActiveRecord::TestCase fixtures :companies, :people diff --git a/activerecord/test/cases/connection_pool_test.rb b/activerecord/test/cases/connection_pool_test.rb index 2da51ea015..1cf215017b 100644 --- a/activerecord/test/cases/connection_pool_test.rb +++ b/activerecord/test/cases/connection_pool_test.rb @@ -142,7 +142,7 @@ module ActiveRecord connections = @pool.connections.dup connections.each do |conn| - conn.extend(Module.new { def active?; false; end; }) + conn.extend(Module.new { def active_threadsafe?; false; end; }) end @pool.reap diff --git a/activerecord/test/cases/fixtures_test.rb b/activerecord/test/cases/fixtures_test.rb index f3a4887a85..37c6af74da 100644 --- a/activerecord/test/cases/fixtures_test.rb +++ b/activerecord/test/cases/fixtures_test.rb @@ -628,7 +628,9 @@ class LoadAllFixturesTest < ActiveRecord::TestCase self.class.fixture_path = FIXTURES_ROOT + "/all" self.class.fixtures :all - assert_equal %w(admin/accounts admin/users developers people tasks), fixture_table_names.sort + if File.symlink? FIXTURES_ROOT + "/all/admin" + assert_equal %w(admin/accounts admin/users developers people tasks), fixture_table_names.sort + end ensure ActiveRecord::FixtureSet.reset_cache end @@ -639,7 +641,9 @@ class LoadAllFixturesWithPathnameTest < ActiveRecord::TestCase self.class.fixture_path = Pathname.new(FIXTURES_ROOT).join('all') self.class.fixtures :all - assert_equal %w(admin/accounts admin/users developers people tasks), fixture_table_names.sort + if File.symlink? FIXTURES_ROOT + "/all/admin" + assert_equal %w(admin/accounts admin/users developers people tasks), fixture_table_names.sort + end ensure ActiveRecord::FixtureSet.reset_cache end diff --git a/activerecord/test/cases/reaper_test.rb b/activerecord/test/cases/reaper_test.rb index e53a27d5dd..b62a41c08e 100644 --- a/activerecord/test/cases/reaper_test.rb +++ b/activerecord/test/cases/reaper_test.rb @@ -69,7 +69,7 @@ module ActiveRecord conn = pool.checkout count = pool.connections.length - conn.extend(Module.new { def active?; false; end; }) + conn.extend(Module.new { def active_threadsafe?; false; end; }) while count == pool.connections.length Thread.pass diff --git a/activerecord/test/models/electron.rb b/activerecord/test/models/electron.rb index 35af9f679b..6fc270673f 100644 --- a/activerecord/test/models/electron.rb +++ b/activerecord/test/models/electron.rb @@ -1,3 +1,5 @@ class Electron < ActiveRecord::Base belongs_to :molecule + + validates_presence_of :name end diff --git a/activerecord/test/models/molecule.rb b/activerecord/test/models/molecule.rb index 69325b8d29..26870c8f88 100644 --- a/activerecord/test/models/molecule.rb +++ b/activerecord/test/models/molecule.rb @@ -1,4 +1,6 @@ class Molecule < ActiveRecord::Base belongs_to :liquid has_many :electrons + + accepts_nested_attributes_for :electrons end diff --git a/activerecord/test/models/pirate.rb b/activerecord/test/models/pirate.rb index 7bb0caf44b..8510c596a7 100644 --- a/activerecord/test/models/pirate.rb +++ b/activerecord/test/models/pirate.rb @@ -85,3 +85,11 @@ end class DestructivePirate < Pirate has_one :dependent_ship, :class_name => 'Ship', :foreign_key => :pirate_id, :dependent => :destroy end + +class FamousPirate < ActiveRecord::Base + self.table_name = 'pirates' + + has_many :famous_ships + + validates_presence_of :catchphrase, on: :conference +end diff --git a/activerecord/test/models/ship.rb b/activerecord/test/models/ship.rb index 3da031946f..7a369b9d9a 100644 --- a/activerecord/test/models/ship.rb +++ b/activerecord/test/models/ship.rb @@ -17,3 +17,11 @@ class Ship < ActiveRecord::Base false end end + +class FamousShip < ActiveRecord::Base + self.table_name = 'ships' + + belongs_to :famous_pirate + + validates_presence_of :name, on: :conference +end diff --git a/activesupport/lib/active_support/dependencies.rb b/activesupport/lib/active_support/dependencies.rb index 6be19771f5..7ea3ff7d3f 100644 --- a/activesupport/lib/active_support/dependencies.rb +++ b/activesupport/lib/active_support/dependencies.rb @@ -665,6 +665,14 @@ module ActiveSupport #:nodoc: constants = normalized.split('::') to_remove = constants.pop + # Remove the file path from the loaded list. + file_path = search_for_file(const.underscore) + if file_path + expanded = File.expand_path(file_path) + expanded.sub!(/\.rb\z/, '') + self.loaded.delete(expanded) + end + if constants.empty? parent = Object else diff --git a/activesupport/lib/active_support/multibyte/unicode.rb b/activesupport/lib/active_support/multibyte/unicode.rb index 84799c2399..7e518d8c39 100644 --- a/activesupport/lib/active_support/multibyte/unicode.rb +++ b/activesupport/lib/active_support/multibyte/unicode.rb @@ -213,7 +213,7 @@ module ActiveSupport end # Ruby >= 2.1 has String#scrub, which is faster than the workaround used for < 2.1. - if RUBY_VERSION >= '2.1' + if '<3'.respond_to?(:scrub) # Replaces all ISO-8859-1 or CP1252 characters by their UTF-8 equivalent # resulting in a valid UTF-8 string. # diff --git a/activesupport/test/dependencies_test.rb b/activesupport/test/dependencies_test.rb index 00bec5bd9d..4ca63b3417 100644 --- a/activesupport/test/dependencies_test.rb +++ b/activesupport/test/dependencies_test.rb @@ -948,6 +948,18 @@ class DependenciesTest < ActiveSupport::TestCase Object.class_eval { remove_const :A if const_defined?(:A) } end + def test_access_unloaded_constants_for_reload + with_autoloading_fixtures do + assert_kind_of Module, A + assert_kind_of Class, A::B # Necessary to load A::B for the test + ActiveSupport::Dependencies.mark_for_unload(A::B) + ActiveSupport::Dependencies.remove_unloadable_constants! + + A::B # Make sure no circular dependency error + end + end + + def test_autoload_once_paths_should_behave_when_recursively_loading with_loading 'dependencies', 'autoloading_fixtures' do ActiveSupport::Dependencies.autoload_once_paths = [ActiveSupport::Dependencies.autoload_paths.last] diff --git a/guides/source/getting_started.md b/guides/source/getting_started.md index 738bf0be4d..3e560bdd86 100644 --- a/guides/source/getting_started.md +++ b/guides/source/getting_started.md @@ -367,10 +367,10 @@ styling for it afterwards. ### Laying down the ground work -Firstly, you need a place within the application to create a new article. A -great place for that would be at `/articles/new`. With the route already -defined, requests can now be made to `/articles/new` in the application. -Navigate to <http://localhost:3000/articles/new> and you'll see a routing +Firstly, you need a place within the application to create a new article. A +great place for that would be at `/articles/new`. With the route already +defined, requests can now be made to `/articles/new` in the application. +Navigate to <http://localhost:3000/articles/new> and you'll see a routing error: ![Another routing error, uninitialized constant ArticlesController](images/getting_started/routing_error_no_controller.png) |