Permalink
Browse files

Ensure identity map is cleared with error [ #2445 ]

  • Loading branch information...
1 parent 2463d66 commit 542d2c48a142435254a021a27715b58a987934c9 @durran durran committed Nov 7, 2012
View
@@ -1,2 +1,3 @@
# encoding: utf-8
+require "rack/mongoid/proxy"
require "rack/mongoid/middleware/identity_map"
@@ -31,9 +31,14 @@ def initialize(app)
#
# @since 2.1.0
def call(env)
- response = @app.call(env)
- response[2] = ::Rack::BodyProxy.new(response[2]) do
+ begin
+ response = @app.call(env)
+ response[2] = ::Rack::Mongoid::Proxy.new(response[2]) do
+ ::Mongoid::IdentityMap.clear
+ end
+ rescue
::Mongoid::IdentityMap.clear
+ raise
end
response
end
View
@@ -0,0 +1,43 @@
+# encoding: utf-8
+module Rack
+ module Mongoid
+
+ # Override the Rack::BodyProxy to ensure that our passed block gets
+ # executed even when exceptions are raised.
+ class Proxy < Rack::BodyProxy
+
+ # Rack's implementation of this method ensures that the block is called
+ # here, but in the case of an error close might not get called. We remove
+ # the block call here.
+ #
+ # @example Close the body.
+ # proxy.close
+ #
+ # @return [ Object ] The result of the body close.
+ #
+ # @since 3.0.12
+ def close
+ return if @closed
+ @closed = true
+ @body.close if @body.respond_to?(:close)
+ end
+
+ # We ensure here that the block is called that we passed to the
+ # constructor unless the body is already closed.
+ #
+ # @param [ Array<Object ] args The arguments for each.
+ #
+ # @return [ Object ] The result of body.each.
+ #
+ # @since 3.0.12
+ def each(*args, &block)
+ @body.each(*args, &block)
+ ensure
+ unless @closed
+ @closed = true
+ @block.call
+ end
+ end
+ end
+ end
+end
@@ -22,8 +22,36 @@
module Rack
class BodyProxy
- def initialize(response, &block)
- @response, @block = response, block
+ def initialize(body, &block)
+ @body, @block, @closed = body, block, false
+ end
+
+ def respond_to?(*args)
+ return false if args.first.to_s =~ /^to_ary$/
+ super or @body.respond_to?(*args)
+ end
+
+ def close
+ return if @closed
+ @closed = true
+ begin
+ @body.close if @body.respond_to? :close
+ ensure
+ @block.call
+ end
+ end
+
+ def closed?
+ @closed
+ end
+
+ def each(*args, &block)
+ @body.each(*args, &block)
+ end
+
+ def method_missing(*args, &block)
+ super if args.first.to_s =~ /^to_ary$/
+ @body.__send__(*args, &block)
end
end
end

0 comments on commit 542d2c4

Please sign in to comment.