diff options
-rw-r--r-- | actionview/lib/action_view/helpers/asset_url_helper.rb | 2 | ||||
-rw-r--r-- | actionview/test/template/asset_tag_helper_test.rb | 11 | ||||
-rw-r--r-- | activerecord/CHANGELOG.md | 8 | ||||
-rw-r--r-- | activerecord/lib/active_record/connection_adapters/abstract/transaction.rb | 16 | ||||
-rw-r--r-- | activerecord/test/cases/transactions_test.rb | 31 |
5 files changed, 62 insertions, 6 deletions
diff --git a/actionview/lib/action_view/helpers/asset_url_helper.rb b/actionview/lib/action_view/helpers/asset_url_helper.rb index 9e8d005ec7..29733442c1 100644 --- a/actionview/lib/action_view/helpers/asset_url_helper.rb +++ b/actionview/lib/action_view/helpers/asset_url_helper.rb @@ -121,8 +121,8 @@ module ActionView # asset_path "application", type: :stylesheet # => /assets/application.css # asset_path "http://www.example.com/js/xmlhr.js" # => http://www.example.com/js/xmlhr.js def asset_path(source, options = {}) - return "" unless source.present? source = source.to_s + return "" unless source.present? return source if source =~ URI_REGEXP tail, source = source[/([\?#].+)$/], source.sub(/([\?#].+)$/, '') diff --git a/actionview/test/template/asset_tag_helper_test.rb b/actionview/test/template/asset_tag_helper_test.rb index d789a5ca27..df8547ef85 100644 --- a/actionview/test/template/asset_tag_helper_test.rb +++ b/actionview/test/template/asset_tag_helper_test.rb @@ -535,6 +535,17 @@ class AssetTagHelperTest < ActionView::TestCase assert_equal copy, source end + class PlaceholderImage + def blank?; true; end + def to_s; 'no-image-yet.png'; end + end + def test_image_tag_with_blank_placeholder + assert_equal '<img alt="" src="/images/no-image-yet.png" />', image_tag(PlaceholderImage.new, alt: "") + end + def test_image_path_with_blank_placeholder + assert_equal '/images/no-image-yet.png', image_path(PlaceholderImage.new) + end + def test_image_path_with_asset_host_proc_returning_nil @controller.config.asset_host = Proc.new do |source| unless source.end_with?("tiff") diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md index 13e8292954..40eb32c059 100644 --- a/activerecord/CHANGELOG.md +++ b/activerecord/CHANGELOG.md @@ -1,3 +1,11 @@ +* When a thread is killed, rollback the active transaction, instead of + committing it during the stack unwind. Previously, we could commit half- + completed work. This fix only works for Ruby 2.0+; on 1.9, we can't + distinguish a thread kill from an ordinary non-local (block) return, so must + default to committing. + + *Chris Hanks* + * A `NullRelation` should represent nothing. This fixes a bug where `Comment.where(post_id: Post.none)` returned a non-empty result. diff --git a/activerecord/lib/active_record/connection_adapters/abstract/transaction.rb b/activerecord/lib/active_record/connection_adapters/abstract/transaction.rb index 90be835d8a..fd666c8c39 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/transaction.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/transaction.rb @@ -190,11 +190,17 @@ module ActiveRecord rollback_transaction if transaction raise ensure - begin - commit_transaction unless error - rescue Exception - transaction.rollback unless transaction.state.completed? - raise + unless error + if Thread.current.status == 'aborting' + rollback_transaction + else + begin + commit_transaction + rescue Exception + transaction.rollback unless transaction.state.completed? + raise + end + end end end diff --git a/activerecord/test/cases/transactions_test.rb b/activerecord/test/cases/transactions_test.rb index 9cfe041de2..5cccf2dda5 100644 --- a/activerecord/test/cases/transactions_test.rb +++ b/activerecord/test/cases/transactions_test.rb @@ -492,6 +492,37 @@ class TransactionTest < ActiveRecord::TestCase assert topic.frozen?, 'not frozen' end + # The behavior of killed threads having a status of "aborting" was changed + # in Ruby 2.0, so Thread#kill on 1.9 will prematurely commit the transaction + # and there's nothing we can do about it. + unless RUBY_VERSION.start_with? '1.9' + def test_rollback_when_thread_killed + queue = Queue.new + thread = Thread.new do + Topic.transaction do + @first.approved = true + @second.approved = false + @first.save + + queue.push nil + sleep + + @second.save + end + end + + queue.pop + thread.kill + thread.join + + assert @first.approved?, "First should still be changed in the objects" + assert !@second.approved?, "Second should still be changed in the objects" + + assert !Topic.find(1).approved?, "First shouldn't have been approved" + assert Topic.find(2).approved?, "Second should still be approved" + end + end + def test_restore_active_record_state_for_all_records_in_a_transaction topic_without_callbacks = Class.new(ActiveRecord::Base) do self.table_name = 'topics' |