aboutsummaryrefslogtreecommitdiffstats
path: root/actionpack/lib/action_dispatch
diff options
context:
space:
mode:
Diffstat (limited to 'actionpack/lib/action_dispatch')
-rw-r--r--actionpack/lib/action_dispatch/middleware/closed_error.rb7
-rw-r--r--actionpack/lib/action_dispatch/middleware/cookies.rb28
-rw-r--r--actionpack/lib/action_dispatch/middleware/flash.rb68
-rw-r--r--actionpack/lib/action_dispatch/middleware/session/abstract_store.rb4
-rw-r--r--actionpack/lib/action_dispatch/middleware/static.rb43
-rw-r--r--actionpack/lib/action_dispatch/routing/mapper.rb5
-rw-r--r--actionpack/lib/action_dispatch/testing/assertions/response.rb4
-rw-r--r--actionpack/lib/action_dispatch/testing/assertions/selector.rb204
-rw-r--r--actionpack/lib/action_dispatch/testing/integration.rb28
9 files changed, 134 insertions, 257 deletions
diff --git a/actionpack/lib/action_dispatch/middleware/closed_error.rb b/actionpack/lib/action_dispatch/middleware/closed_error.rb
new file mode 100644
index 0000000000..0a4db47f4b
--- /dev/null
+++ b/actionpack/lib/action_dispatch/middleware/closed_error.rb
@@ -0,0 +1,7 @@
+module ActionDispatch
+ class ClosedError < StandardError #:nodoc:
+ def initialize(kind)
+ super "Cannot modify #{kind} because it was closed. This means it was already streamed back to the client or converted to HTTP headers."
+ end
+ end
+end
diff --git a/actionpack/lib/action_dispatch/middleware/cookies.rb b/actionpack/lib/action_dispatch/middleware/cookies.rb
index 7ac608f0a8..24ebb8fed7 100644
--- a/actionpack/lib/action_dispatch/middleware/cookies.rb
+++ b/actionpack/lib/action_dispatch/middleware/cookies.rb
@@ -83,7 +83,7 @@ module ActionDispatch
# Raised when storing more than 4K of session data.
class CookieOverflow < StandardError; end
- class CookieJar < Hash #:nodoc:
+ class CookieJar #:nodoc:
# This regular expression is used to split the levels of a domain.
# The top level domain can be any string without a period or
@@ -115,13 +115,22 @@ module ActionDispatch
@delete_cookies = {}
@host = host
@secure = secure
-
- super()
+ @closed = false
+ @cookies = {}
end
+ attr_reader :closed
+ alias :closed? :closed
+ def close!; @closed = true end
+
# Returns the value of the cookie by +name+, or +nil+ if no such cookie exists.
def [](name)
- super(name.to_s)
+ @cookies[name.to_s]
+ end
+
+ def update(other_hash)
+ @cookies.update other_hash
+ self
end
def handle_options(options) #:nodoc:
@@ -145,6 +154,7 @@ module ActionDispatch
# Sets the cookie named +name+. The second argument may be the very cookie
# value, or a hash of options as documented above.
def []=(key, options)
+ raise ClosedError, :cookies if closed?
if options.is_a?(Hash)
options.symbolize_keys!
value = options[:value]
@@ -153,7 +163,7 @@ module ActionDispatch
options = { :value => value }
end
- value = super(key.to_s, value)
+ value = @cookies[key.to_s] = value
handle_options(options)
@@ -170,7 +180,7 @@ module ActionDispatch
handle_options(options)
- value = super(key.to_s)
+ value = @cookies.delete(key.to_s)
@delete_cookies[key] = options
value
end
@@ -225,6 +235,7 @@ module ActionDispatch
end
def []=(key, options)
+ raise ClosedError, :cookies if closed?
if options.is_a?(Hash)
options.symbolize_keys!
else
@@ -263,6 +274,7 @@ module ActionDispatch
end
def []=(key, options)
+ raise ClosedError, :cookies if closed?
if options.is_a?(Hash)
options.symbolize_keys!
options[:value] = @verifier.generate(options[:value])
@@ -305,6 +317,7 @@ module ActionDispatch
end
def call(env)
+ cookie_jar = nil
status, headers, body = @app.call(env)
if cookie_jar = env['action_dispatch.cookies']
@@ -315,6 +328,9 @@ module ActionDispatch
end
[status, headers, body]
+ ensure
+ cookie_jar = ActionDispatch::Request.new(env).cookie_jar unless cookie_jar
+ cookie_jar.close!
end
end
end
diff --git a/actionpack/lib/action_dispatch/middleware/flash.rb b/actionpack/lib/action_dispatch/middleware/flash.rb
index 21aeeb217a..027ff7f8ac 100644
--- a/actionpack/lib/action_dispatch/middleware/flash.rb
+++ b/actionpack/lib/action_dispatch/middleware/flash.rb
@@ -43,9 +43,15 @@ module ActionDispatch
class FlashNow #:nodoc:
def initialize(flash)
@flash = flash
+ @closed = false
end
+ attr_reader :closed
+ alias :closed? :closed
+ def close!; @closed = true end
+
def []=(k, v)
+ raise ClosedError, :flash if closed?
@flash[k] = v
@flash.discard(k)
v
@@ -66,27 +72,70 @@ module ActionDispatch
end
end
- class FlashHash < Hash
+ class FlashHash
+ include Enumerable
+
def initialize #:nodoc:
- super
- @used = Set.new
+ @used = Set.new
+ @closed = false
+ @flashes = {}
end
+ attr_reader :closed
+ alias :closed? :closed
+ def close!; @closed = true end
+
def []=(k, v) #:nodoc:
+ raise ClosedError, :flash if closed?
keep(k)
- super
+ @flashes[k] = v
+ end
+
+ def [](k)
+ @flashes[k]
end
def update(h) #:nodoc:
h.keys.each { |k| keep(k) }
- super
+ @flashes.update h
+ self
+ end
+
+ def keys
+ @flashes.keys
+ end
+
+ def key?(name)
+ @flashes.key? name
+ end
+
+ def delete(key)
+ @flashes.delete key
+ self
+ end
+
+ def to_hash
+ @flashes.dup
+ end
+
+ def empty?
+ @flashes.empty?
+ end
+
+ def clear
+ @flashes.clear
+ end
+
+ def each(&block)
+ @flashes.each(&block)
end
alias :merge! :update
def replace(h) #:nodoc:
@used = Set.new
- super
+ @flashes.replace h
+ self
end
# Sets a flash that will not be available to the next action, only to the current.
@@ -100,7 +149,7 @@ module ActionDispatch
#
# Entries set via <tt>now</tt> are accessed the same way as standard entries: <tt>flash['my-key']</tt>.
def now
- FlashNow.new(self)
+ @now ||= FlashNow.new(self)
end
# Keeps either the entire current flash or a specific flash entry available for the next action:
@@ -184,8 +233,11 @@ module ActionDispatch
session = env['rack.session'] || {}
flash_hash = env['action_dispatch.request.flash_hash']
- if flash_hash && (!flash_hash.empty? || session.key?('flash'))
+ if flash_hash
+ if !flash_hash.empty? || session.key?('flash')
session["flash"] = flash_hash
+ end
+ flash_hash.close!
end
if session.key?('flash') && session['flash'].empty?
diff --git a/actionpack/lib/action_dispatch/middleware/session/abstract_store.rb b/actionpack/lib/action_dispatch/middleware/session/abstract_store.rb
index 64d3a87fd0..1a811ce1b1 100644
--- a/actionpack/lib/action_dispatch/middleware/session/abstract_store.rb
+++ b/actionpack/lib/action_dispatch/middleware/session/abstract_store.rb
@@ -29,7 +29,9 @@ module ActionDispatch
end
def generate_sid
- ActiveSupport::SecureRandom.hex(16)
+ sid = ActiveSupport::SecureRandom.hex(16)
+ sid.encode!('UTF-8') if sid.respond_to?(:encode!)
+ sid
end
protected
diff --git a/actionpack/lib/action_dispatch/middleware/static.rb b/actionpack/lib/action_dispatch/middleware/static.rb
index c57f694c4d..348f7b86b8 100644
--- a/actionpack/lib/action_dispatch/middleware/static.rb
+++ b/actionpack/lib/action_dispatch/middleware/static.rb
@@ -2,25 +2,23 @@ require 'rack/utils'
module ActionDispatch
class FileHandler
- def initialize(at, root)
- @at, @root = at.chomp('/'), root.chomp('/')
- @compiled_at = @at.blank? ? nil : /^#{Regexp.escape(at)}/
+ def initialize(root)
+ @root = root.chomp('/')
@compiled_root = /^#{Regexp.escape(root)}/
@file_server = ::Rack::File.new(@root)
end
def match?(path)
path = path.dup
- if !@compiled_at || path.sub!(@compiled_at, '')
- full_path = path.empty? ? @root : File.join(@root, ::Rack::Utils.unescape(path))
- paths = "#{full_path}#{ext}"
- matches = Dir[paths]
- match = matches.detect { |m| File.file?(m) }
- if match
- match.sub!(@compiled_root, '')
- match
- end
+ full_path = path.empty? ? @root : File.join(@root, ::Rack::Utils.unescape(path))
+ paths = "#{full_path}#{ext}"
+
+ matches = Dir[paths]
+ match = matches.detect { |m| File.file?(m) }
+ if match
+ match.sub!(@compiled_root, '')
+ match
end
end
@@ -39,9 +37,9 @@ module ActionDispatch
class Static
FILE_METHODS = %w(GET HEAD).freeze
- def initialize(app, roots)
+ def initialize(app, path)
@app = app
- @file_handlers = create_file_handlers(roots)
+ @file_handler = FileHandler.new(path)
end
def call(env)
@@ -49,24 +47,13 @@ module ActionDispatch
method = env['REQUEST_METHOD']
if FILE_METHODS.include?(method)
- @file_handlers.each do |file_handler|
- if match = file_handler.match?(path)
- env["PATH_INFO"] = match
- return file_handler.call(env)
- end
+ if match = @file_handler.match?(path)
+ env["PATH_INFO"] = match
+ return @file_handler.call(env)
end
end
@app.call(env)
end
-
- private
- def create_file_handlers(roots)
- roots = { '' => roots } unless roots.is_a?(Hash)
-
- roots.map do |at, root|
- FileHandler.new(at, root) if File.exist?(root)
- end.compact
- end
end
end
diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb
index 35be0b3a27..a65f6e1fce 100644
--- a/actionpack/lib/action_dispatch/routing/mapper.rb
+++ b/actionpack/lib/action_dispatch/routing/mapper.rb
@@ -1,6 +1,7 @@
require 'erb'
require 'active_support/core_ext/hash/except'
require 'active_support/core_ext/object/blank'
+require 'active_support/core_ext/object/inclusion'
require 'active_support/inflector'
require 'action_dispatch/routing/redirection'
@@ -1345,11 +1346,11 @@ module ActionDispatch
end
def resource_scope? #:nodoc:
- [:resource, :resources].include?(@scope[:scope_level])
+ @scope[:scope_level].in?([:resource, :resources])
end
def resource_method_scope? #:nodoc:
- [:collection, :member, :new].include?(@scope[:scope_level])
+ @scope[:scope_level].in?([:collection, :member, :new])
end
def with_exclusive_scope
diff --git a/actionpack/lib/action_dispatch/testing/assertions/response.rb b/actionpack/lib/action_dispatch/testing/assertions/response.rb
index 77a15f3e97..8a04cfa886 100644
--- a/actionpack/lib/action_dispatch/testing/assertions/response.rb
+++ b/actionpack/lib/action_dispatch/testing/assertions/response.rb
@@ -1,3 +1,5 @@
+require 'active_support/core_ext/object/inclusion'
+
module ActionDispatch
module Assertions
# A small suite of assertions that test responses from \Rails applications.
@@ -33,7 +35,7 @@ module ActionDispatch
def assert_response(type, message = nil)
validate_request!
- if [ :success, :missing, :redirect, :error ].include?(type) && @response.send("#{type}?")
+ if type.in?([:success, :missing, :redirect, :error]) && @response.send("#{type}?")
assert_block("") { true } # to count the assertion
elsif type.is_a?(Fixnum) && @response.response_code == type
assert_block("") { true } # to count the assertion
diff --git a/actionpack/lib/action_dispatch/testing/assertions/selector.rb b/actionpack/lib/action_dispatch/testing/assertions/selector.rb
index 2b862fb7d6..c67a0664dc 100644
--- a/actionpack/lib/action_dispatch/testing/assertions/selector.rb
+++ b/actionpack/lib/action_dispatch/testing/assertions/selector.rb
@@ -1,4 +1,5 @@
require 'action_controller/vendor/html-scanner'
+require 'active_support/core_ext/object/inclusion'
#--
# Copyright (c) 2006 Assaf Arkin (http://labnotes.org)
@@ -18,7 +19,7 @@ module ActionDispatch
# from the response HTML or elements selected by the enclosing assertion.
#
# In addition to HTML responses, you can make the following assertions:
- # * +assert_select_rjs+ - Assertions on HTML content of RJS update and insertion operations.
+ #
# * +assert_select_encoded+ - Assertions on HTML encoded inside XML, for example for dealing with feed item descriptions.
# * +assert_select_email+ - Assertions on the HTML body of an e-mail.
#
@@ -79,7 +80,7 @@ module ActionDispatch
return matches
else
- root = response_from_page_or_rjs
+ root = response_from_page
end
case arg
@@ -203,7 +204,7 @@ module ActionDispatch
root.children.concat @selected
else
# Otherwise just operate on the response document.
- root = response_from_page_or_rjs
+ root = response_from_page
end
# First or second argument is the selector: string and we pass
@@ -325,144 +326,6 @@ module ActionDispatch
end
end
- # Selects content from the RJS response.
- #
- # === Narrowing down
- #
- # With no arguments, asserts that one or more elements are updated or
- # inserted by RJS statements.
- #
- # Use the +id+ argument to narrow down the assertion to only statements
- # that update or insert an element with that identifier.
- #
- # Use the first argument to narrow down assertions to only statements
- # of that type. Possible values are <tt>:replace</tt>, <tt>:replace_html</tt>,
- # <tt>:show</tt>, <tt>:hide</tt>, <tt>:toggle</tt>, <tt>:remove</tta>,
- # <tt>:insert_html</tt> and <tt>:redirect</tt>.
- #
- # Use the argument <tt>:insert</tt> followed by an insertion position to narrow
- # down the assertion to only statements that insert elements in that
- # position. Possible values are <tt>:top</tt>, <tt>:bottom</tt>, <tt>:before</tt>
- # and <tt>:after</tt>.
- #
- # Use the argument <tt>:redirect</tt> followed by a path to check that an statement
- # which redirects to the specified path is generated.
- #
- # Using the <tt>:remove</tt> statement, you will be able to pass a block, but it will
- # be ignored as there is no HTML passed for this statement.
- #
- # === Using blocks
- #
- # Without a block, +assert_select_rjs+ merely asserts that the response
- # contains one or more RJS statements that replace or update content.
- #
- # With a block, +assert_select_rjs+ also selects all elements used in
- # these statements and passes them to the block. Nested assertions are
- # supported.
- #
- # Calling +assert_select_rjs+ with no arguments and using nested asserts
- # asserts that the HTML content is returned by one or more RJS statements.
- # Using +assert_select+ directly makes the same assertion on the content,
- # but without distinguishing whether the content is returned in an HTML
- # or JavaScript.
- #
- # ==== Examples
- #
- # # Replacing the element foo.
- # # page.replace 'foo', ...
- # assert_select_rjs :replace, "foo"
- #
- # # Replacing with the chained RJS proxy.
- # # page[:foo].replace ...
- # assert_select_rjs :chained_replace, 'foo'
- #
- # # Inserting into the element bar, top position.
- # assert_select_rjs :insert, :top, "bar"
- #
- # # Remove the element bar
- # assert_select_rjs :remove, "bar"
- #
- # # Changing the element foo, with an image.
- # assert_select_rjs "foo" do
- # assert_select "img[src=/images/logo.gif""
- # end
- #
- # # RJS inserts or updates a list with four items.
- # assert_select_rjs do
- # assert_select "ol>li", 4
- # end
- #
- # # The same, but shorter.
- # assert_select "ol>li", 4
- #
- # # Checking for a redirect.
- # assert_select_rjs :redirect, root_path
- def assert_select_rjs(*args, &block)
- rjs_type = args.first.is_a?(Symbol) ? args.shift : nil
- id = args.first.is_a?(String) ? args.shift : nil
-
- # If the first argument is a symbol, it's the type of RJS statement we're looking
- # for (update, replace, insertion, etc). Otherwise, we're looking for just about
- # any RJS statement.
- if rjs_type
- if rjs_type == :insert
- position = args.shift
- id = args.shift
- insertion = "insert_#{position}".to_sym
- raise ArgumentError, "Unknown RJS insertion type #{position}" unless RJS_STATEMENTS[insertion]
- statement = "(#{RJS_STATEMENTS[insertion]})"
- else
- raise ArgumentError, "Unknown RJS statement type #{rjs_type}" unless RJS_STATEMENTS[rjs_type]
- statement = "(#{RJS_STATEMENTS[rjs_type]})"
- end
- else
- statement = "#{RJS_STATEMENTS[:any]}"
- end
-
- # Next argument we're looking for is the element identifier. If missing, we pick
- # any element, otherwise we replace it in the statement.
- pattern = Regexp.new(
- id ? statement.gsub(RJS_ANY_ID, "\"#{id}\"") : statement
- )
-
- # Duplicate the body since the next step involves destroying it.
- matches = nil
- case rjs_type
- when :remove, :show, :hide, :toggle
- matches = @response.body.match(pattern)
- else
- @response.body.gsub(pattern) do |match|
- html = unescape_rjs(match)
- matches ||= []
- matches.concat HTML::Document.new(html).root.children.select { |n| n.tag? }
- ""
- end
- end
-
- if matches
- assert_block("") { true } # to count the assertion
- if block_given? && !([:remove, :show, :hide, :toggle].include? rjs_type)
- begin
- @selected ||= nil
- in_scope, @selected = @selected, matches
- yield matches
- ensure
- @selected = in_scope
- end
- end
- matches
- else
- # RJS statement not found.
- case rjs_type
- when :remove, :show, :hide, :toggle
- flunk_message = "No RJS statement that #{rjs_type.to_s}s '#{id}' was rendered."
- else
- flunk_message = "No RJS statement that replaces or inserts HTML content."
- end
- flunk args.shift || flunk_message
- end
- end
-
# Extracts the content of an element, treats it as encoded HTML and runs
# nested assertion on it.
#
@@ -562,62 +425,9 @@ module ActionDispatch
end
protected
- RJS_PATTERN_HTML = "\"((\\\\\"|[^\"])*)\""
- RJS_ANY_ID = "\"([^\"])*\""
- RJS_STATEMENTS = {
- :chained_replace => "\\$\\(#{RJS_ANY_ID}\\)\\.replace\\(#{RJS_PATTERN_HTML}\\)",
- :chained_replace_html => "\\$\\(#{RJS_ANY_ID}\\)\\.update\\(#{RJS_PATTERN_HTML}\\)",
- :replace_html => "Element\\.update\\(#{RJS_ANY_ID}, #{RJS_PATTERN_HTML}\\)",
- :replace => "Element\\.replace\\(#{RJS_ANY_ID}, #{RJS_PATTERN_HTML}\\)",
- :redirect => "window.location.href = #{RJS_ANY_ID}"
- }
- [:remove, :show, :hide, :toggle].each do |action|
- RJS_STATEMENTS[action] = "Element\\.#{action}\\(#{RJS_ANY_ID}\\)"
- end
- RJS_INSERTIONS = ["top", "bottom", "before", "after"]
- RJS_INSERTIONS.each do |insertion|
- RJS_STATEMENTS["insert_#{insertion}".to_sym] = "Element.insert\\(#{RJS_ANY_ID}, \\{ #{insertion}: #{RJS_PATTERN_HTML} \\}\\)"
- end
- RJS_STATEMENTS[:insert_html] = "Element.insert\\(#{RJS_ANY_ID}, \\{ (#{RJS_INSERTIONS.join('|')}): #{RJS_PATTERN_HTML} \\}\\)"
- RJS_STATEMENTS[:any] = Regexp.new("(#{RJS_STATEMENTS.values.join('|')})")
- RJS_PATTERN_UNICODE_ESCAPED_CHAR = /\\u([0-9a-zA-Z]{4})/
-
- # +assert_select+ and +css_select+ call this to obtain the content in the HTML
- # page, or from all the RJS statements, depending on the type of response.
- def response_from_page_or_rjs()
- content_type = @response.content_type
-
- if content_type && Mime::JS =~ content_type
- body = @response.body.dup
- root = HTML::Node.new(nil)
-
- while true
- next if body.sub!(RJS_STATEMENTS[:any]) do |match|
- html = unescape_rjs(match)
- matches = HTML::Document.new(html).root.children.select { |n| n.tag? }
- root.children.concat matches
- ""
- end
- break
- end
-
- root
- else
- html_document.root
- end
- end
-
- # Unescapes a RJS string.
- def unescape_rjs(rjs_string)
- # RJS encodes double quotes and line breaks.
- unescaped= rjs_string.gsub('\"', '"')
- unescaped.gsub!(/\\\//, '/')
- unescaped.gsub!('\n', "\n")
- unescaped.gsub!('\076', '>')
- unescaped.gsub!('\074', '<')
- # RJS encodes non-ascii characters.
- unescaped.gsub!(RJS_PATTERN_UNICODE_ESCAPED_CHAR) {|u| [$1.hex].pack('U*')}
- unescaped
+ # +assert_select+ and +css_select+ call this to obtain the content in the HTML page.
+ def response_from_page
+ html_document.root
end
end
end
diff --git a/actionpack/lib/action_dispatch/testing/integration.rb b/actionpack/lib/action_dispatch/testing/integration.rb
index 5c6416a19e..7d707d03a9 100644
--- a/actionpack/lib/action_dispatch/testing/integration.rb
+++ b/actionpack/lib/action_dispatch/testing/integration.rb
@@ -1,6 +1,7 @@
require 'stringio'
require 'uri'
require 'active_support/core_ext/kernel/singleton_class'
+require 'active_support/core_ext/object/inclusion'
require 'active_support/core_ext/object/try'
require 'rack/test'
require 'test/unit/assertions'
@@ -26,31 +27,31 @@ module ActionDispatch
# object's <tt>@response</tt> instance variable will point to the same
# response object.
#
- # You can also perform POST, PUT, DELETE, and HEAD requests with +post+,
- # +put+, +delete+, and +head+.
+ # You can also perform POST, PUT, DELETE, and HEAD requests with +#post+,
+ # +#put+, +#delete+, and +#head+.
def get(path, parameters = nil, headers = nil)
process :get, path, parameters, headers
end
- # Performs a POST request with the given parameters. See get() for more
+ # Performs a POST request with the given parameters. See +#get+ for more
# details.
def post(path, parameters = nil, headers = nil)
process :post, path, parameters, headers
end
- # Performs a PUT request with the given parameters. See get() for more
+ # Performs a PUT request with the given parameters. See +#get+ for more
# details.
def put(path, parameters = nil, headers = nil)
process :put, path, parameters, headers
end
- # Performs a DELETE request with the given parameters. See get() for
+ # Performs a DELETE request with the given parameters. See +#get+ for
# more details.
def delete(path, parameters = nil, headers = nil)
process :delete, path, parameters, headers
end
- # Performs a HEAD request with the given parameters. See get() for more
+ # Performs a HEAD request with the given parameters. See +#get+ for more
# details.
def head(path, parameters = nil, headers = nil)
process :head, path, parameters, headers
@@ -59,7 +60,7 @@ module ActionDispatch
# Performs an XMLHttpRequest request with the given parameters, mirroring
# a request from the Prototype library.
#
- # The request_method is :get, :post, :put, :delete or :head; the
+ # The request_method is +:get+, +:post+, +:put+, +:delete+ or +:head+; the
# parameters are +nil+, a hash, or a url-encoded or multipart string;
# the headers are a hash. Keys are automatically upcased and prefixed
# with 'HTTP_' if not already.
@@ -243,7 +244,8 @@ module ActionDispatch
end
# Performs the actual request.
- def process(method, path, parameters = nil, rack_environment = nil)
+ def process(method, path, parameters = nil, env = nil)
+ env ||= {}
if path =~ %r{://}
location = URI.parse(path)
https! URI::HTTPS === location if location.scheme
@@ -259,7 +261,7 @@ module ActionDispatch
hostname, port = host.split(':')
- env = {
+ default_env = {
:method => method,
:params => parameters,
@@ -277,9 +279,7 @@ module ActionDispatch
session = Rack::Test::Session.new(_mock_session)
- (rack_environment || {}).each do |key, value|
- env[key] = value
- end
+ env.reverse_merge!(default_env)
# NOTE: rack-test v0.5 doesn't build a default uri correctly
# Make sure requested path is always a full uri
@@ -321,7 +321,7 @@ module ActionDispatch
define_method(method) do |*args|
reset! unless integration_session
# reset the html_document variable, but only for new get/post calls
- @html_document = nil unless %w(cookies assigns).include?(method)
+ @html_document = nil unless method.in?(["cookies", "assigns"])
integration_session.__send__(method, *args).tap do
copy_session_variables!
end
@@ -384,7 +384,7 @@ module ActionDispatch
end
end
- # An test that spans multiple controllers and actions,
+ # An integration test spans multiple controllers and actions,
# tying them all together to ensure they work together as expected. It tests
# more completely than either unit or functional tests do, exercising the
# entire stack, from the dispatcher to the database.