Permalink
Browse files

Merge remote-tracking branch 'upstream/master'

* upstream/master: (91 commits)
  Responders now return 204 No Content for API requests without a response body (as in the new scaffold)
  Scaffold returns 204 No Content for API requests without content. This makes scaffold work with jQuery out of the box.
  Fix failing tests.
  properly handle lists of lists. Thanks @adrianpike for reporting!
  Fix that changing a store should mark the store attribute as changed
  Clean up .gitignore and make a note about using global ignores
  Revert "Ignore .rbx directories (rbx compiled bytecode files)"
  Revert "Merge pull request #3395 from bdurand/fix_file_store_cleanup"
  Fix deprecation warnings in action pack test suite due to passing template formats in the template name.
  safeguard against configs missing environment or the database key
  Remove needless to_param in scaffold functional test
  Unused variable removed
  minor revision to some new code in databases.rake
  registers PR #2419 in the CHANGELOG
  ActionPack test fix for RBX
  Ignore .rbx directories (rbx compiled bytecode files)
  edge doesnt provide turn gem in the gemfile anymore
  Remove Turn from default Gemfile.
  Revert "Merge pull request #3405 from arunagw/middleware_name"
  minor fixes in the composed_of doc
  ...

Conflicts:
	.gitignore
  • Loading branch information...
2 parents d28e1b8 + 408bbfe commit 79123aa67f48e546fb96d3c64f738aac30b10676 @georgeG committed Oct 26, 2011
Showing with 1,290 additions and 284 deletions.
  1. +22 −4 .gitignore
  2. +1 −6 Gemfile
  3. +1 −1 actionmailer/lib/action_mailer/base.rb
  4. +4 −0 actionpack/CHANGELOG
  5. +2 −2 actionpack/actionpack.gemspec
  6. +1 −21 actionpack/lib/action_controller/metal/responder.rb
  7. +2 −2 actionpack/lib/action_controller/record_identifier.rb
  8. +1 −1 actionpack/lib/action_controller/vendor/html-scanner/html/document.rb
  9. +2 −0 actionpack/lib/action_dispatch.rb
  10. +10 −0 actionpack/lib/action_dispatch/http/request.rb
  11. +1 −1 actionpack/lib/action_dispatch/middleware/cookies.rb
  12. +39 −0 actionpack/lib/action_dispatch/middleware/request_id.rb
  13. +50 −0 actionpack/lib/action_dispatch/middleware/session/cache_store.rb
  14. +6 −1 actionpack/lib/action_view/helpers/form_options_helper.rb
  15. +13 −11 actionpack/test/controller/mime_responds_test.rb
  16. +65 −0 actionpack/test/dispatch/request_id_test.rb
  17. +181 −0 actionpack/test/dispatch/session/cache_store_test.rb
  18. +9 −0 actionpack/test/template/form_options_helper_test.rb
  19. +6 −1 actionpack/test/template/html-scanner/tag_node_test.rb
  20. +4 −4 actionpack/test/template/render_test.rb
  21. +2 −0 activemodel/CHANGELOG
  22. +25 −10 activemodel/lib/active_model/errors.rb
  23. +43 −0 activemodel/test/cases/errors_test.rb
  24. +8 −0 activerecord/CHANGELOG
  25. +4 −3 activerecord/lib/active_record/aggregations.rb
  26. +5 −5 activerecord/lib/active_record/associations.rb
  27. +50 −12 activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
  28. +3 −0 activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb
  29. +3 −2 activerecord/lib/active_record/nested_attributes.rb
  30. +16 −11 activerecord/lib/active_record/railties/databases.rake
  31. +1 −0 activerecord/lib/active_record/store.rb
  32. +8 −0 activerecord/test/cases/adapters/postgresql/schema_test.rb
  33. +16 −0 activerecord/test/cases/adapters/postgresql/statement_pool_test.rb
  34. +38 −0 activerecord/test/cases/migration_test.rb
  35. +8 −0 activerecord/test/cases/nested_attributes_test.rb
  36. +5 −0 activerecord/test/cases/store_test.rb
  37. +7 −0 activesupport/CHANGELOG
  38. +1 −0 activesupport/lib/active_support.rb
  39. +36 −8 activesupport/lib/active_support/buffered_logger.rb
  40. +3 −3 activesupport/lib/active_support/core_ext/array/conversions.rb
  41. +14 −3 activesupport/lib/active_support/core_ext/string/inflections.rb
  42. +63 −0 activesupport/lib/active_support/tagged_logging.rb
  43. +53 −0 activesupport/test/buffered_logger_test.rb
  44. +8 −4 activesupport/test/core_ext/string_ext_test.rb
  45. +67 −0 activesupport/test/tagged_logging_test.rb
  46. +4 −0 railties/CHANGELOG
  47. +12 −3 railties/README.rdoc
  48. +0 −5 railties/guides/code/getting_started/Gemfile
  49. +4 −1 railties/guides/code/getting_started/config/environments/production.rb
  50. +6 −4 railties/guides/source/action_controller_overview.textile
  51. +8 −0 railties/guides/source/active_support_core_extensions.textile
  52. +1 −1 railties/guides/source/asset_pipeline.textile
  53. +8 −8 railties/guides/source/command_line.textile
  54. +1 −1 railties/guides/source/configuring.textile
  55. +221 −8 railties/guides/source/engines.textile
  56. +2 −2 railties/guides/source/initialization.textile
  57. +37 −37 railties/guides/source/layouts_and_rendering.textile
  58. +3 −2 railties/guides/source/rails_on_rack.textile
  59. +2 −2 railties/guides/source/security.textile
  60. +2 −1 railties/lib/rails/application.rb
  61. +2 −2 railties/lib/rails/application/bootstrap.rb
  62. +1 −1 railties/lib/rails/application/configuration.rb
  63. +1 −1 railties/lib/rails/commands/server.rb
  64. +1 −12 railties/lib/rails/generators/app_base.rb
  65. +0 −2 railties/lib/rails/generators/rails/app/app_generator.rb
  66. +0 −2 railties/lib/rails/generators/rails/app/templates/Gemfile
  67. +4 −1 railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt
  68. +2 −2 railties/lib/rails/generators/rails/scaffold_controller/templates/controller.rb
  69. +4 −4 railties/lib/rails/generators/test_unit/scaffold/templates/functional_test.rb
  70. +0 −1 railties/lib/rails/rack.rb
  71. +0 −38 railties/lib/rails/rack/content_length.rb
  72. +26 −12 railties/lib/rails/rack/logger.rb
  73. +1 −0 railties/lib/rails/tasks/engine.rake
  74. +1 −0 railties/test/application/middleware_test.rb
  75. +2 −0 railties/test/application/rack/logger_test.rb
  76. +10 −15 railties/test/generators/app_generator_test.rb
  77. +17 −0 railties/test/railties/shared_tests.rb
View
@@ -1,6 +1,6 @@
-pkg
-.bundle
-Gemfile.lock
+# Don't put *.swp, *.bak, etc here; those belong in a global ~/.gitignore.
+# Check out http://help.github.com/ignore-files/ for how to set that up.
+
debug.log
doc/rdoc
activemodel/doc
@@ -25,4 +25,22 @@ railties/tmp
.rbenv-version
RDOC_MAIN.rdoc
.DS_Store
-*.swp
+/.bundle
+/.rbenv-version
+/.rvmrc
+/Gemfile.lock
+/pkg
+/dist
+/doc/rdoc
+/*/doc
+/*/test/tmp
+/activerecord/sqlnet.log
+/activemodel/test/fixtures/fixture_database.sqlite3
+/activesupport/test/fixtures/isolation_test
+/railties/test/500.html
+/railties/test/fixtures/tmp
+/railties/test/initializer/root/log
+/railties/doc
+/railties/guides/output
+/railties/tmp
+/RDOC_MAIN.rdoc
View
@@ -19,12 +19,7 @@ end
# it being automatically loaded by sprockets
gem "uglifier", ">= 1.0.3", :require => false
-# Temp fix until rake 0.9.3 is out
-if RUBY_VERSION >= "1.9.3"
- gem "rake", "0.9.3.beta.1"
-else
- gem "rake", ">= 0.8.7"
-end
+gem "rake", ">= 0.8.7"
gem "mocha", ">= 0.9.8"
group :doc do
@@ -524,7 +524,7 @@ def attachments
#
# * <tt>:subject</tt> - The subject of the message, if this is omitted, Action Mailer will
# ask the Rails I18n class for a translated <tt>:subject</tt> in the scope of
- # <tt>[:actionmailer, mailer_scope, action_name]</tt> or if this is missing, will translate the
+ # <tt>[mailer_scope, action_name]</tt> or if this is missing, will translate the
# humanized version of the <tt>action_name</tt>
# * <tt>:to</tt> - Who the message is destined for, can be a string of addresses, or an array
# of addresses.
View
@@ -1,5 +1,9 @@
*Rails 3.2.0 (unreleased)*
+* Responders now return 204 No Content for API requests without a response body (as in the new scaffold) [José Valim]
+
+* Added ActionDispatch::RequestId middleware that'll make a unique X-Request-Id header available to the response and enables the ActionDispatch::Request#uuid method. This makes it easy to trace requests from end-to-end in the stack and to identify individual requests in mixed logs like Syslog [DHH]
+
* Limit the number of options for select_year to 1000.
Pass the :max_years_allowed option to set your own limit.
@@ -21,10 +21,10 @@ Gem::Specification.new do |s|
s.add_dependency('rack-cache', '~> 1.1')
s.add_dependency('builder', '~> 3.0.0')
s.add_dependency('i18n', '~> 0.6')
- s.add_dependency('rack', '~> 1.3.2')
+ s.add_dependency('rack', '~> 1.3.5')
s.add_dependency('rack-test', '~> 0.6.1')
s.add_dependency('journey', '~> 1.0.0')
- s.add_dependency('sprockets', '~> 2.0.2')
+ s.add_dependency('sprockets', '~> 2.0.3')
s.add_dependency('erubis', '~> 2.7.0')
s.add_development_dependency('tzinfo', '~> 0.3.29')
@@ -202,10 +202,8 @@ def api_behavior(error)
display resource
elsif post?
display resource, :status => :created, :location => api_location
- elsif has_empty_resource_definition?
- display empty_resource, :status => :ok
else
- head :ok
+ head :no_content
end
end
@@ -269,24 +267,6 @@ def default_action
@action ||= ACTIONS_FOR_VERBS[request.request_method_symbol]
end
- # Check whether resource needs a specific definition of empty resource to be valid
- #
- def has_empty_resource_definition?
- respond_to?("empty_#{format}_resource")
- end
-
- # Delegate to proper empty resource method
- #
- def empty_resource
- send("empty_#{format}_resource")
- end
-
- # Return a valid empty JSON resource
- #
- def empty_json_resource
- "{}"
- end
-
def resource_errors
respond_to?("#{format}_resource_errors") ? send("#{format}_resource_errors") : resource.errors
end
@@ -14,9 +14,9 @@ module ActionController
# <% end %> </div>
#
# # controller
- # def destroy
+ # def update
# post = Post.find(params[:id])
- # post.destroy
+ # post.update_attributes(params[:post])
#
# redirect_to(post) # Calls polymorphic_url(post) which in turn calls post_url(post)
# end
@@ -4,7 +4,7 @@
require 'html/sanitizer'
module HTML #:nodoc:
- # A top-level HTMl document. You give it a body of text, and it will parse that
+ # A top-level HTML document. You give it a body of text, and it will parse that
# text into a tree of nodes.
class Document #:nodoc:
@@ -47,6 +47,7 @@ module ActionDispatch
end
autoload_under 'middleware' do
+ autoload :RequestId
autoload :BestStandardsSupport
autoload :Callbacks
autoload :Cookies
@@ -82,6 +83,7 @@ module Session
autoload :AbstractStore, 'action_dispatch/middleware/session/abstract_store'
autoload :CookieStore, 'action_dispatch/middleware/session/cookie_store'
autoload :MemCacheStore, 'action_dispatch/middleware/session/mem_cache_store'
+ autoload :CacheStore, 'action_dispatch/middleware/session/cache_store'
end
autoload_under 'testing' do
@@ -177,6 +177,16 @@ def remote_ip
@remote_ip ||= (@env["action_dispatch.remote_ip"] || ip).to_s
end
+ # Returns the unique request id, which is based off either the X-Request-Id header that can
+ # be generated by a firewall, load balancer, or web server or by the RequestId middleware
+ # (which sets the action_dispatch.request_id environment variable).
+ #
+ # This unique ID is useful for tracing a request from end-to-end as part of logging or debugging.
+ # This relies on the rack variable set by the ActionDispatch::RequestId middleware.
+ def uuid
+ @uuid ||= env["action_dispatch.request_id"]
+ end
+
# Returns the lowercase name of the HTTP server software.
def server_software
(@env['SERVER_SOFTWARE'] && /^([a-zA-Z]+)/ =~ @env['SERVER_SOFTWARE']) ? $1.downcase : nil
@@ -174,7 +174,7 @@ def []=(key, options)
options = { :value => value }
end
- value = @cookies[key.to_s] = value
+ @cookies[key.to_s] = value
handle_options(options)
@@ -0,0 +1,39 @@
+require 'securerandom'
+require 'active_support/core_ext/string/access'
+require 'active_support/core_ext/object/blank'
+
+module ActionDispatch
+ # Makes a unique request id available to the action_dispatch.request_id env variable (which is then accessible through
+ # ActionDispatch::Request#uuid) and sends the same id to the client via the X-Request-Id header.
+ #
+ # The unique request id is either based off the X-Request-Id header in the request, which would typically be generated
+ # by a firewall, load balancer, or the web server, or, if this header is not available, a random uuid. If the
+ # header is accepted from the outside world, we sanitize it to a max of 255 chars and alphanumeric and dashes only.
+ #
+ # The unique request id can be used to trace a request end-to-end and would typically end up being part of log files
+ # from multiple pieces of the stack.
+ class RequestId
+ def initialize(app)
+ @app = app
+ end
+
+ def call(env)
+ env["action_dispatch.request_id"] = external_request_id(env) || internal_request_id
+ status, headers, body = @app.call(env)
+
+ headers["X-Request-Id"] = env["action_dispatch.request_id"]
+ [ status, headers, body ]
+ end
+
+ private
+ def external_request_id(env)
+ if request_id = env["HTTP_X_REQUEST_ID"].presence
+ request_id.gsub(/[^\w\-]/, "").first(255)
+ end
+ end
+
+ def internal_request_id
+ SecureRandom.hex(16)
+ end
+ end
+end
@@ -0,0 +1,50 @@
+require 'action_dispatch/middleware/session/abstract_store'
+require 'rack/session/memcache'
+
+module ActionDispatch
+ module Session
+ # Session store that uses an ActiveSupport::Cache::Store to store the sessions. This store is most useful
+ # if you don't store critical data in your sessions and you don't need them to live for extended periods
+ # of time.
+ class CacheStore < AbstractStore
+ # Create a new store. The cache to use can be passed in the <tt>:cache</tt> option. If it is
+ # not specified, <tt>Rails.cache</tt> will be used.
+ def initialize(app, options = {})
+ @cache = options[:cache] || Rails.cache
+ options[:expire_after] ||= @cache.options[:expires_in]
+ super
+ end
+
+ # Get a session from the cache.
+ def get_session(env, sid)
+ sid ||= generate_sid
+ session = @cache.read(cache_key(sid))
+ session ||= {}
+ [sid, session]
+ end
+
+ # Set a session in the cache.
+ def set_session(env, sid, session, options)
+ key = cache_key(sid)
+ if session
+ @cache.write(key, session, :expires_in => options[:expire_after])
+ else
+ @cache.delete(key)
+ end
+ sid
+ end
+
+ # Remove a session from the cache.
+ def destroy_session(env, sid, options)
+ @cache.delete(cache_key(sid))
+ generate_sid
+ end
+
+ private
+ # Turn the session id into a cache key.
+ def cache_key(sid)
+ "_session_id:#{sid}"
+ end
+ end
+ end
+end
@@ -579,7 +579,12 @@ class InstanceTag #:nodoc:
def to_select_tag(choices, options, html_options)
selected_value = options.has_key?(:selected) ? options[:selected] : value(object)
- if !choices.empty? && Array === choices.first
+ # Grouped choices look like this:
+ #
+ # [nil, []]
+ # { nil => [] }
+ #
+ if !choices.empty? && choices.first.last.respond_to?(:each)
option_tags = grouped_options_for_select(choices, :selected => selected_value, :disabled => options[:disabled])
else
option_tags = options_for_select(choices, :selected => selected_value, :disabled => options[:disabled])
@@ -656,7 +656,9 @@ def test_using_hash_resource
@request.accept = "application/json"
get :using_hash_resource
assert_equal "application/json", @response.content_type
- assert_equal %Q[{"result":{"name":"david","id":13}}], @response.body
+ assert @response.body.include?("result")
+ assert @response.body.include?('"name":"david"')
+ assert @response.body.include?('"id":13')
end
def test_using_hash_resource_with_post
@@ -794,21 +796,21 @@ def test_using_resource_for_put_with_html_rerender_on_failure_even_on_method_ove
end
end
- def test_using_resource_for_put_with_xml_yields_ok_on_success
+ def test_using_resource_for_put_with_xml_yields_no_content_on_success
@request.accept = "application/xml"
put :using_resource
assert_equal "application/xml", @response.content_type
- assert_equal 200, @response.status
+ assert_equal 204, @response.status
assert_equal " ", @response.body
end
- def test_using_resource_for_put_with_json_yields_ok_on_success
+ def test_using_resource_for_put_with_json_yields_no_content_on_success
Customer.any_instance.stubs(:to_json).returns('{"name": "David"}')
@request.accept = "application/json"
put :using_resource
assert_equal "application/json", @response.content_type
- assert_equal 200, @response.status
- assert_equal "{}", @response.body
+ assert_equal 204, @response.status
+ assert_equal " ", @response.body
end
def test_using_resource_for_put_with_xml_yields_unprocessable_entity_on_failure
@@ -844,23 +846,23 @@ def test_using_resource_for_delete_with_html_redirects_on_success
end
end
- def test_using_resource_for_delete_with_xml_yields_ok_on_success
+ def test_using_resource_for_delete_with_xml_yields_no_content_on_success
Customer.any_instance.stubs(:destroyed?).returns(true)
@request.accept = "application/xml"
delete :using_resource
assert_equal "application/xml", @response.content_type
- assert_equal 200, @response.status
+ assert_equal 204, @response.status
assert_equal " ", @response.body
end
- def test_using_resource_for_delete_with_json_yields_ok_on_success
+ def test_using_resource_for_delete_with_json_yields_no_content_on_success
Customer.any_instance.stubs(:to_json).returns('{"name": "David"}')
Customer.any_instance.stubs(:destroyed?).returns(true)
@request.accept = "application/json"
delete :using_resource
assert_equal "application/json", @response.content_type
- assert_equal 200, @response.status
- assert_equal "{}", @response.body
+ assert_equal 204, @response.status
+ assert_equal " ", @response.body
end
def test_using_resource_for_delete_with_html_redirects_on_failure
Oops, something went wrong.

0 comments on commit 79123aa

Please sign in to comment.