Permalink
Browse files

Merge branch 'master' into nested_has_many_through

Conflicts:
	activerecord/lib/active_record/associations.rb
  • Loading branch information...
jonleighton committed Nov 8, 2010
2 parents 083d6f2 + 4e0477c commit e05162cffad7ae86615c21c6b54ab161d0261c39
Showing with 381 additions and 185 deletions.
  1. +5 −0 Gemfile
  2. +1 −1 actionpack/lib/action_controller/metal/mime_responds.rb
  3. +0 −9 actionpack/lib/action_controller/metal/testing.rb
  4. +3 −2 actionpack/lib/action_controller/test_case.rb
  5. +19 −2 actionpack/lib/action_dispatch/http/request.rb
  6. +3 −2 actionpack/lib/action_dispatch/routing/mapper.rb
  7. +1 −1 actionpack/lib/action_dispatch/testing/test_process.rb
  8. +2 −1 actionpack/lib/action_view/helpers/capture_helper.rb
  9. +1 −2 actionpack/lib/action_view/helpers/form_helper.rb
  10. +21 −10 actionpack/lib/action_view/helpers/number_helper.rb
  11. +6 −1 actionpack/lib/action_view/template/handlers/erb.rb
  12. +16 −0 actionpack/test/controller/mime_responds_test.rb
  13. +7 −0 actionpack/test/controller/new_base/bare_metal_test.rb
  14. +10 −0 actionpack/test/controller/new_base/render_template_test.rb
  15. +18 −0 actionpack/test/dispatch/cookies_test.rb
  16. +31 −0 actionpack/test/dispatch/routing_test.rb
  17. +10 −0 actionpack/test/template/capture_helper_test.rb
  18. +4 −1 actionpack/test/template/number_helper_i18n_test.rb
  19. +4 −0 actionpack/test/template/number_helper_test.rb
  20. +1 −6 actionpack/test/template/url_helper_test.rb
  21. +7 −0 activemodel/test/cases/serializeration/xml_serialization_test.rb
  22. +18 −20 activerecord/lib/active_record/associations.rb
  23. +1 −1 activerecord/lib/active_record/associations/association_proxy.rb
  24. +1 −1 activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb
  25. +2 −2 activerecord/lib/active_record/connection_adapters/mysql_adapter.rb
  26. +8 −8 activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
  27. +11 −11 activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb
  28. +6 −4 activerecord/lib/active_record/relation/finder_methods.rb
  29. +1 −1 activerecord/lib/active_record/timestamp.rb
  30. +17 −25 activerecord/lib/active_record/validations/uniqueness.rb
  31. +13 −13 activerecord/test/cases/adapters/mysql/connection_test.rb
  32. +9 −9 activerecord/test/cases/adapters/postgresql/postgresql_adapter_test.rb
  33. +2 −2 activerecord/test/cases/adapters/postgresql/schema_authorization_test.rb
  34. +12 −12 activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb
  35. +1 −1 activerecord/test/cases/associations/cascaded_eager_loading_test.rb
  36. +2 −2 activerecord/test/cases/associations/eager_test.rb
  37. +1 −1 activerecord/test/cases/base_test.rb
  38. +14 −0 activerecord/test/cases/dirty_test.rb
  39. +7 −3 activerecord/test/cases/helper.rb
  40. +5 −5 activerecord/test/cases/reflection_test.rb
  41. +12 −1 activerecord/test/cases/relations_test.rb
  42. +0 −12 activerecord/test/connections/native_oracle/connection.rb
  43. +1 −0 activerecord/test/schema/schema.rb
  44. +3 −4 activesupport/lib/active_support/cache/file_store.rb
  45. +4 −2 activesupport/lib/active_support/hash_with_indifferent_access.rb
  46. +2 −0 activesupport/lib/active_support/ordered_hash.rb
  47. +4 −2 activesupport/lib/active_support/xml_mini.rb
  48. +9 −0 activesupport/test/caching_test.rb
  49. +22 −2 activesupport/test/core_ext/hash_ext_test.rb
  50. +8 −0 activesupport/test/ordered_hash_test.rb
  51. +14 −2 activesupport/test/test_xml_mini.rb
  52. +1 −1 railties/railties.gemspec
View
@@ -31,6 +31,11 @@ platforms :mri_18 do
gem 'ruby-prof'
end
+platforms :mri_19 do
+ # TODO: Remove the conditional when ruby-debug19 supports Ruby >= 1.9.3
+ gem "ruby-debug19" if RUBY_VERSION < "1.9.3"
+end
+
platforms :ruby do
gem 'json'
gem 'yajl-ruby'
@@ -227,7 +227,7 @@ def respond_with(*resources, &block)
"controller responds to in the class level" if self.class.mimes_for_respond_to.empty?
if response = retrieve_response_from_mimes(&block)
- options = resources.extract_options!
+ options = resources.size == 1 ? {} : resources.extract_options!
options.merge!(:default_response => response)
(options.delete(:responder) || self.class.responder).call(self, resources, options)
end
@@ -14,18 +14,9 @@ def process_with_new_base_test(request, response)
cookies.write(@_response)
end
@_response.prepare!
- set_test_assigns
ret
end
- def set_test_assigns
- @assigns = {}
- (instance_variable_names - self.class.protected_instance_variables).each do |var|
- name, value = var[1..-1], instance_variable_get(var)
- @assigns[name] = value
- end
- end
-
# TODO : Rewrite tests using controller.headers= to use Rack env
def headers=(new_headers)
@_response ||= ActionDispatch::Response.new
@@ -411,8 +411,9 @@ def process(action, parameters = nil, session = nil, flash = nil, http_method =
@controller.request = @request
@controller.params.merge!(parameters)
build_request_uri(action, parameters)
- Base.class_eval { include Testing }
+ @controller.class.class_eval { include Testing }
@controller.process_with_new_base_test(@request, @response)
+ @assigns = @controller.respond_to?(:view_assigns) ? @controller.view_assigns : {}
@request.session.delete('flash') if @request.session['flash'].blank?
@response
end
@@ -448,7 +449,7 @@ def rescue_action_in_public!
def build_request_uri(action, parameters)
unless @request.env["PATH_INFO"]
- options = @controller.__send__(:url_options).merge(parameters)
+ options = @controller.respond_to?(:url_options) ? @controller.__send__(:url_options).merge(parameters) : parameters
options.update(
:only_path => true,
:action => action,
@@ -4,6 +4,7 @@
require 'active_support/core_ext/hash/indifferent_access'
require 'active_support/core_ext/string/access'
+require 'active_support/inflector'
require 'action_dispatch/http/headers'
module ActionDispatch
@@ -44,8 +45,24 @@ def key?(key)
@env.key?(key)
end
- HTTP_METHODS = %w(get head put post delete options)
- HTTP_METHOD_LOOKUP = HTTP_METHODS.inject({}) { |h, m| h[m] = h[m.upcase] = m.to_sym; h }
+ # List of HTTP request methods from the following RFCs:
+ # Hypertext Transfer Protocol -- HTTP/1.1 (http://www.ietf.org/rfc/rfc2616.txt)
+ # HTTP Extensions for Distributed Authoring -- WEBDAV (http://www.ietf.org/rfc/rfc2518.txt)
+ # Versioning Extensions to WebDAV (http://www.ietf.org/rfc/rfc3253.txt)
+ # Ordered Collections Protocol (WebDAV) (http://www.ietf.org/rfc/rfc3648.txt)
+ # Web Distributed Authoring and Versioning (WebDAV) Access Control Protocol (http://www.ietf.org/rfc/rfc3744.txt)
+ # Web Distributed Authoring and Versioning (WebDAV) SEARCH (http://www.ietf.org/rfc/rfc5323.txt)
+ # PATCH Method for HTTP (http://www.ietf.org/rfc/rfc5789.txt)
+ RFC2616 = %w(OPTIONS GET HEAD POST PUT DELETE TRACE CONNECT)
+ RFC2518 = %w(PROPFIND PROPPATCH MKCOL COPY MOVE LOCK UNLOCK)
+ RFC3253 = %w(VERSION-CONTROL REPORT CHECKOUT CHECKIN UNCHECKOUT MKWORKSPACE UPDATE LABEL MERGE BASELINE-CONTROL MKACTIVITY)
+ RFC3648 = %w(ORDERPATCH)
+ RFC3744 = %w(ACL)
+ RFC5323 = %w(SEARCH)
+ RFC5789 = %w(PATCH)
+
+ HTTP_METHODS = RFC2616 + RFC2518 + RFC3253 + RFC3648 + RFC3744 + RFC5323 + RFC5789
+ HTTP_METHOD_LOOKUP = Hash.new { |h, m| h[m] = m.underscore.to_sym if HTTP_METHODS.include?(m) }
# Returns the HTTP \method that the application should see.
# In the case where the \method was overridden by a middleware
@@ -1,6 +1,7 @@
require 'erb'
require 'active_support/core_ext/hash/except'
require 'active_support/core_ext/object/blank'
+require 'active_support/inflector'
module ActionDispatch
module Routing
@@ -186,8 +187,8 @@ def constraints
def request_method_condition
if via = @options[:via]
- via = Array(via).map { |m| m.to_s.upcase }
- { :request_method => Regexp.union(*via) }
+ via = Array(via).map { |m| m.to_s.dasherize.upcase }
+ { :request_method => %r[^#{via.join('|')}$] }
else
{ }
end
@@ -22,7 +22,7 @@ def flash
end
def cookies
- @request.cookies.merge(@response.cookies)
+ HashWithIndifferentAccess.new(@request.cookies.merge(@response.cookies))
end
def redirect_to_url
@@ -1,4 +1,5 @@
require 'active_support/core_ext/object/blank'
+require 'active_support/core_ext/string/output_safety'
module ActionView
# = Action View Capture Helper
@@ -38,7 +39,7 @@ def capture(*args)
value = nil
buffer = with_output_buffer { value = yield(*args) }
if string = buffer.presence || value and string.is_a?(String)
- string
+ ERB::Util.html_escape string
end
end
@@ -294,10 +294,9 @@ module FormHelper
#
# If you don't need to attach a form to a model instance, then check out
# FormTagHelper#form_tag.
- def form_for(record, options = nil, &proc)
+ def form_for(record, options = {}, &proc)
raise ArgumentError, "Missing block" unless block_given?
- options ||= {}
options[:html] ||= {}
case record
@@ -15,7 +15,7 @@ module Helpers #:nodoc:
# unchanged if can't be converted into a valid number.
module NumberHelper
- DEFAULT_CURRENCY_VALUES = { :format => "%u%n", :unit => "$", :separator => ".", :delimiter => ",",
+ DEFAULT_CURRENCY_VALUES = { :format => "%u%n", :negative_format => "-%u%n", :unit => "$", :separator => ".", :delimiter => ",",
:precision => 2, :significant => false, :strip_insignificant_zeros => false }
# Raised when argument +number+ param given to the helpers is invalid and
@@ -81,22 +81,27 @@ def number_to_phone(number, options = {})
# in the +options+ hash.
#
# ==== Options
- # * <tt>:locale</tt> - Sets the locale to be used for formatting (defaults to current locale).
- # * <tt>:precision</tt> - Sets the level of precision (defaults to 2).
- # * <tt>:unit</tt> - Sets the denomination of the currency (defaults to "$").
- # * <tt>:separator</tt> - Sets the separator between the units (defaults to ".").
- # * <tt>:delimiter</tt> - Sets the thousands delimiter (defaults to ",").
- # * <tt>:format</tt> - Sets the format of the output string (defaults to "%u%n"). The field types are:
- #
- # %u The currency unit
- # %n The number
+ # * <tt>:locale</tt> - Sets the locale to be used for formatting (defaults to current locale).
+ # * <tt>:precision</tt> - Sets the level of precision (defaults to 2).
+ # * <tt>:unit</tt> - Sets the denomination of the currency (defaults to "$").
+ # * <tt>:separator</tt> - Sets the separator between the units (defaults to ".").
+ # * <tt>:delimiter</tt> - Sets the thousands delimiter (defaults to ",").
+ # * <tt>:format</tt> - Sets the format for non-negative numbers (defaults to "%u%n").
+ # Fields are <tt>%u</tt> for the currency, and <tt>%n</tt>
+ # for the number.
+ # * <tt>:negative_format</tt> - Sets the format for negative numbers (defaults to prepending
+ # an hyphen to the formatted number given by <tt>:format</tt>).
+ # Accepts the same fields than <tt>:format</tt>, except
+ # <tt>%n</tt> is here the absolute value of the number.
#
# ==== Examples
# number_to_currency(1234567890.50) # => $1,234,567,890.50
# number_to_currency(1234567890.506) # => $1,234,567,890.51
# number_to_currency(1234567890.506, :precision => 3) # => $1,234,567,890.506
# number_to_currency(1234567890.506, :locale => :fr) # => 1 234 567 890,506 €
#
+ # number_to_currency(1234567890.50, :negative_format => "(%u%n)")
+ # # => ($1,234,567,890.51)
# number_to_currency(1234567890.50, :unit => "&pound;", :separator => ",", :delimiter => "")
# # => &pound;1234567890,50
# number_to_currency(1234567890.50, :unit => "&pound;", :separator => ",", :delimiter => "", :format => "%n %u")
@@ -110,11 +115,17 @@ def number_to_currency(number, options = {})
currency = I18n.translate(:'number.currency.format', :locale => options[:locale], :default => {})
defaults = DEFAULT_CURRENCY_VALUES.merge(defaults).merge!(currency)
+ defaults[:negative_format] = "-" + options[:format] if options[:format]
options = defaults.merge!(options)
unit = options.delete(:unit)
format = options.delete(:format)
+ if number.to_f < 0
+ format = options.delete(:negative_format)
+ number = number.respond_to?("abs") ? number.abs : number.sub(/^-/, '')
+ end
+
begin
value = number_with_precision(number, options.merge(:raise => true))
format.gsub(/%n/, value).gsub(/%u/, unit).html_safe
@@ -15,6 +15,7 @@ def <<(value)
super(value.to_s)
end
alias :append= :<<
+ alias :safe_append= :safe_concat
end
class Template
@@ -40,7 +41,11 @@ def add_expr_literal(src, code)
end
def add_expr_escaped(src, code)
- src << '@output_buffer.append= ' << escaped_expr(code) << ';'
+ if code =~ BLOCK_EXPR
+ src << "@output_buffer.safe_append= " << code
+ else
+ src << "@output_buffer.safe_concat((" << code << ").to_s);"
+ end
end
def add_postamble(src)
@@ -487,6 +487,10 @@ def using_resource
respond_with(resource)
end
+ def using_hash_resource
+ respond_with({:result => resource})
+ end
+
def using_resource_with_block
respond_with(resource) do |format|
format.csv { render :text => "CSV" }
@@ -587,6 +591,18 @@ def test_using_resource
end
end
+ def test_using_hash_resource
+ @request.accept = "application/xml"
+ get :using_hash_resource
+ assert_equal "application/xml", @response.content_type
+ assert_equal "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<hash>\n <name>david</name>\n</hash>\n", @response.body
+
+ @request.accept = "application/json"
+ get :using_hash_resource
+ assert_equal "application/json", @response.content_type
+ assert_equal %Q[{"result":["david",13]}], @response.body
+ end
+
def test_using_resource_with_block
@request.accept = "*/*"
get :using_resource_with_block
@@ -39,4 +39,11 @@ class HeadTest < ActiveSupport::TestCase
assert_equal 404, status
end
end
+
+ class BareControllerTest < ActionController::TestCase
+ test "GET index" do
+ get :index
+ assert_equal "Hello world", @response.body
+ end
+ end
end
@@ -9,6 +9,7 @@ class WithoutLayoutController < ActionController::Base
"locals.html.erb" => "The secret is <%= secret %>",
"xml_template.xml.builder" => "xml.html do\n xml.p 'Hello'\nend",
"with_raw.html.erb" => "Hello <%=raw '<strong>this is raw</strong>' %>",
+ "with_implicit_raw.html.erb"=> "Hello <%== '<strong>this is also raw</strong>' %>",
"test/with_json.html.erb" => "<%= render :template => 'test/with_json.json' %>",
"test/with_json.json.erb" => "<%= render :template => 'test/final' %>",
"test/final.json.erb" => "{ final: json }",
@@ -51,6 +52,10 @@ def with_raw
render :template => "with_raw"
end
+ def with_implicit_raw
+ render :template => "with_implicit_raw"
+ end
+
def with_error
render :template => "test/with_error"
end
@@ -99,6 +104,11 @@ class TestWithoutLayout < Rack::TestCase
assert_body "Hello <strong>this is raw</strong>"
assert_status 200
+
+ get :with_implicit_raw
+
+ assert_body "Hello <strong>this is also raw</strong>"
+ assert_status 200
end
test "rendering a template with renders another template with other format that renders other template in the same format" do
@@ -94,6 +94,16 @@ def delete_cookie_with_domain
cookies.delete(:user_name, :domain => :all)
head :ok
end
+
+ def symbol_key
+ cookies[:user_name] = "david"
+ head :ok
+ end
+
+ def string_key
+ cookies['user_name'] = "david"
+ head :ok
+ end
end
tests TestController
@@ -291,6 +301,14 @@ def test_deleting_cookie_with_all_domain_option
assert_cookie_header "user_name=; domain=.nextangle.com; path=/; expires=Thu, 01-Jan-1970 00:00:00 GMT"
end
+ def test_cookies_hash_is_indifferent_access
+ [:symbol_key, :string_key].each do |cookie_key|
+ get cookie_key
+ assert_equal "david", cookies[:user_name]
+ assert_equal "david", cookies['user_name']
+ end
+ end
+
private
def assert_cookie_header(expected)
header = @response.headers["Set-Cookie"]
@@ -2255,3 +2255,34 @@ def test_default_scope
end
end
+class TestHttpMethods < ActionDispatch::IntegrationTest
+ RFC2616 = %w(OPTIONS GET HEAD POST PUT DELETE TRACE CONNECT)
+ RFC2518 = %w(PROPFIND PROPPATCH MKCOL COPY MOVE LOCK UNLOCK)
+ RFC3253 = %w(VERSION-CONTROL REPORT CHECKOUT CHECKIN UNCHECKOUT MKWORKSPACE UPDATE LABEL MERGE BASELINE-CONTROL MKACTIVITY)
+ RFC3648 = %w(ORDERPATCH)
+ RFC3744 = %w(ACL)
+ RFC5323 = %w(SEARCH)
+ RFC5789 = %w(PATCH)
+
+ def simple_app(response)
+ lambda { |env| [ 200, { 'Content-Type' => 'text/plain' }, [response] ] }
+ end
+
+ setup do
+ s = self
+ @app = ActionDispatch::Routing::RouteSet.new
+
+ @app.draw do
+ (RFC2616 + RFC2518 + RFC3253 + RFC3648 + RFC3744 + RFC5323 + RFC5789).each do |method|
+ match '/' => s.simple_app(method), :via => method.underscore.to_sym
+ end
+ end
+ end
+
+ (RFC2616 + RFC2518 + RFC3253 + RFC3648 + RFC3744 + RFC5323 + RFC5789).each do |method|
+ test "request method #{method.underscore} can be matched" do
+ get '/', nil, 'REQUEST_METHOD' => method
+ assert_equal method, @response.body
+ end
+ end
+end
@@ -28,6 +28,16 @@ def test_capture_returns_nil_if_the_returned_value_is_not_a_string
assert_nil @av.capture { 1 }
end
+ def test_capture_escapes_html
+ string = @av.capture { '<em>bar</em>' }
+ assert_equal '&lt;em&gt;bar&lt;/em&gt;', string
+ end
+
+ def test_capture_doesnt_escape_twice
+ string = @av.capture { '&lt;em&gt;bar&lt;/em&gt;'.html_safe }
+ assert_equal '&lt;em&gt;bar&lt;/em&gt;', string
+ end
+
def test_content_for
assert ! content_for?(:title)
content_for :title, 'title'
Oops, something went wrong.

0 comments on commit e05162c

Please sign in to comment.