actionpack 3.0.1 → 3.0.2

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of actionpack might be problematic. Click here for more details.

Files changed (42) hide show
  1. data/CHANGELOG +7 -1
  2. data/lib/abstract_controller/base.rb +1 -0
  3. data/lib/abstract_controller/callbacks.rb +2 -0
  4. data/lib/abstract_controller/rendering.rb +4 -4
  5. data/lib/action_controller/base.rb +2 -0
  6. data/lib/action_controller/metal.rb +8 -3
  7. data/lib/action_controller/metal/head.rb +2 -4
  8. data/lib/action_controller/metal/http_authentication.rb +8 -10
  9. data/lib/action_controller/metal/mime_responds.rb +1 -1
  10. data/lib/action_controller/metal/redirecting.rb +4 -2
  11. data/lib/action_controller/metal/renderers.rb +1 -1
  12. data/lib/action_controller/metal/responder.rb +20 -0
  13. data/lib/action_controller/test_case.rb +7 -0
  14. data/lib/action_controller/vendor/html-scanner/html/node.rb +5 -11
  15. data/lib/action_dispatch/http/request.rb +19 -2
  16. data/lib/action_dispatch/http/response.rb +9 -10
  17. data/lib/action_dispatch/http/upload.rb +21 -29
  18. data/lib/action_dispatch/middleware/cookies.rb +11 -3
  19. data/lib/action_dispatch/railtie.rb +0 -5
  20. data/lib/action_dispatch/routing.rb +75 -22
  21. data/lib/action_dispatch/routing/mapper.rb +429 -60
  22. data/lib/action_dispatch/routing/polymorphic_routes.rb +1 -1
  23. data/lib/action_dispatch/routing/route.rb +2 -1
  24. data/lib/action_dispatch/routing/url_for.rb +4 -5
  25. data/lib/action_dispatch/testing/integration.rb +9 -7
  26. data/lib/action_pack/version.rb +2 -2
  27. data/lib/action_view/base.rb +1 -1
  28. data/lib/action_view/helpers/asset_tag_helper.rb +1 -1
  29. data/lib/action_view/helpers/capture_helper.rb +2 -1
  30. data/lib/action_view/helpers/date_helper.rb +2 -0
  31. data/lib/action_view/helpers/form_helper.rb +15 -12
  32. data/lib/action_view/helpers/form_options_helper.rb +5 -5
  33. data/lib/action_view/helpers/javascript_helper.rb +2 -1
  34. data/lib/action_view/helpers/number_helper.rb +23 -12
  35. data/lib/action_view/helpers/prototype_helper.rb +4 -4
  36. data/lib/action_view/helpers/text_helper.rb +18 -0
  37. data/lib/action_view/helpers/url_helper.rb +12 -10
  38. data/lib/action_view/render/partials.rb +52 -8
  39. data/lib/action_view/render/rendering.rb +1 -1
  40. data/lib/action_view/template/handlers/erb.rb +6 -1
  41. data/lib/action_view/test_case.rb +26 -10
  42. metadata +35 -12
data/CHANGELOG CHANGED
@@ -1,6 +1,12 @@
1
+ *Rails 3.0.2 (November 15, 2010)*
2
+
3
+ * The helper number_to_currency accepts a new :negative_format option to be able to configure how to render negative amounts. [Don Wilson]
4
+
5
+
1
6
  *Rails 3.0.1 (October 15, 2010)*
2
7
 
3
- * No Changes, just a version bump.
8
+ * No changes.
9
+
4
10
 
5
11
  *Rails 3.0.0 (August 29, 2010)*
6
12
 
@@ -13,6 +13,7 @@ module AbstractController
13
13
  class Base
14
14
  attr_internal :response_body
15
15
  attr_internal :action_name
16
+ attr_internal :formats
16
17
 
17
18
  include ActiveSupport::Configurable
18
19
  extend ActiveSupport::DescendantsTracker
@@ -83,6 +83,7 @@ module AbstractController
83
83
  # for details on the allowed parameters.
84
84
  def #{filter}_filter(*names, &blk) # def before_filter(*names, &blk)
85
85
  _insert_callbacks(names, blk) do |name, options| # _insert_callbacks(names, blk) do |name, options}
86
+ options[:if]=(Array.wrap(options[:if]) << "!halted") if #{filter == :after}
86
87
  set_callback(:process_action, :#{filter}, name, options) # set_callback(:process_action, :before_filter, name, options)
87
88
  end # end
88
89
  end # end
@@ -91,6 +92,7 @@ module AbstractController
91
92
  # for details on the allowed parameters.
92
93
  def prepend_#{filter}_filter(*names, &blk) # def prepend_before_filter(*names, &blk)
93
94
  _insert_callbacks(names, blk) do |name, options| # _insert_callbacks(names, blk) do |name, options|
95
+ options[:if]=(Array.wrap(options[:if]) << "!halted") if #{filter == :after}
94
96
  set_callback(:process_action, :#{filter}, name, options.merge(:prepend => true)) # set_callback(:process_action, :before, name, options.merge(:prepend => true))
95
97
  end # end
96
98
  end # end
@@ -47,13 +47,13 @@ module AbstractController
47
47
  @view_context_class ||= begin
48
48
  controller = self
49
49
  Class.new(ActionView::Base) do
50
+ if controller.respond_to?(:_routes)
51
+ include controller._routes.url_helpers
52
+ end
53
+
50
54
  if controller.respond_to?(:_helpers)
51
55
  include controller._helpers
52
56
 
53
- if controller.respond_to?(:_routes)
54
- include controller._routes.url_helpers
55
- end
56
-
57
57
  # TODO: Fix RJS to not require this
58
58
  self.helpers = controller._helpers
59
59
  end
@@ -148,6 +148,8 @@ module ActionController
148
148
  #
149
149
  # In this case, after saving our new entry to the database, the user is redirected to the <tt>show</tt> method which is then executed.
150
150
  #
151
+ # Learn more about <tt>redirect_to</tt> and what options you have in ActionController::Redirecting.
152
+ #
151
153
  # == Calling multiple redirects or renders
152
154
  #
153
155
  # An action may contain only a single render or a single redirect. Attempting to try to do either again will result in a DoubleRenderError:
@@ -12,7 +12,7 @@ module ActionController
12
12
  #
13
13
  class MiddlewareStack < ActionDispatch::MiddlewareStack #:nodoc:
14
14
  class Middleware < ActionDispatch::MiddlewareStack::Middleware #:nodoc:
15
- def initialize(klass, *args)
15
+ def initialize(klass, *args, &block)
16
16
  options = args.extract_options!
17
17
  @only = Array(options.delete(:only)).map(&:to_s)
18
18
  @except = Array(options.delete(:except)).map(&:to_s)
@@ -112,6 +112,11 @@ module ActionController
112
112
  headers["Location"] = url
113
113
  end
114
114
 
115
+ # basic url_for that can be overridden for more robust functionality
116
+ def url_for(string)
117
+ string
118
+ end
119
+
115
120
  def status
116
121
  @_status
117
122
  end
@@ -147,8 +152,8 @@ module ActionController
147
152
  super
148
153
  end
149
154
 
150
- def self.use(*args)
151
- middleware_stack.use(*args)
155
+ def self.use(*args, &block)
156
+ middleware_stack.use(*args, &block)
152
157
  end
153
158
 
154
159
  def self.middleware
@@ -2,8 +2,6 @@ module ActionController
2
2
  module Head
3
3
  extend ActiveSupport::Concern
4
4
 
5
- include ActionController::UrlFor
6
-
7
5
  # Return a response that has no content (merely headers). The options
8
6
  # argument is interpreted to be a hash of header names and values.
9
7
  # This allows you to easily return a response that consists only of
@@ -27,8 +25,8 @@ module ActionController
27
25
 
28
26
  self.status = status
29
27
  self.location = url_for(location) if location
30
- self.content_type = Mime[formats.first]
28
+ self.content_type = Mime[formats.first] if formats
31
29
  self.response_body = " "
32
30
  end
33
31
  end
34
- end
32
+ end
@@ -95,12 +95,11 @@ module ActionController
95
95
  # end
96
96
  # end
97
97
  #
98
- # NOTE: The +authenticate_or_request_with_http_digest+ block must return the user's password or the ha1 digest hash so the framework can appropriately
99
- # hash to check the user's credentials. Returning +nil+ will cause authentication to fail.
100
- # Storing the ha1 hash: MD5(username:realm:password), is better than storing a plain password. If
101
- # the password file or database is compromised, the attacker would be able to use the ha1 hash to
102
- # authenticate as the user at this +realm+, but would not have the user's password to try using at
103
- # other sites.
98
+ # === Notes
99
+ #
100
+ # The +authenticate_or_request_with_http_digest+ block must return the user's password
101
+ # or the ha1 digest hash so the framework can appropriately hash to check the user's
102
+ # credentials. Returning +nil+ will cause authentication to fail.
104
103
  #
105
104
  # On shared hosts, Apache sometimes doesn't pass authentication headers to
106
105
  # FCGI instances. If your environment matches this description and you cannot
@@ -218,11 +217,10 @@ module ActionController
218
217
  end
219
218
 
220
219
  def decode_credentials(header)
221
- header.to_s.gsub(/^Digest\s+/,'').split(',').inject({}) do |hash, pair|
220
+ Hash[header.to_s.gsub(/^Digest\s+/,'').split(',').map do |pair|
222
221
  key, value = pair.split('=', 2)
223
- hash[key.strip.to_sym] = value.to_s.gsub(/^"|"$/,'').gsub(/'/, '')
224
- hash
225
- end
222
+ [key.strip.to_sym, value.to_s.gsub(/^"|"$/,'').gsub(/'/, '')]
223
+ end]
226
224
  end
227
225
 
228
226
  def authentication_header(controller, realm)
@@ -227,7 +227,7 @@ module ActionController #:nodoc:
227
227
  "controller responds to in the class level" if self.class.mimes_for_respond_to.empty?
228
228
 
229
229
  if response = retrieve_response_from_mimes(&block)
230
- options = resources.extract_options!
230
+ options = resources.size == 1 ? {} : resources.extract_options!
231
231
  options.merge!(:default_response => response)
232
232
  (options.delete(:responder) || self.class.responder).call(self, resources, options)
233
233
  end
@@ -38,6 +38,9 @@ module ActionController
38
38
  # redirect_to :action=>'atom', :status => :moved_permanently
39
39
  # redirect_to post_url(@post), :status => 301
40
40
  # redirect_to :action=>'atom', :status => 302
41
+ #
42
+ # The status code can either be a standard {HTTP Status code}[http://www.iana.org/assignments/http-status-codes] as an
43
+ # integer, or a symbol representing the downcased, underscored and symbolized description.
41
44
  #
42
45
  # It is also possible to assign a flash message as part of the redirection. There are two special accessors for commonly used the flash names
43
46
  # +alert+ and +notice+ as well as a general purpose +flash+ bucket.
@@ -48,8 +51,7 @@ module ActionController
48
51
  # redirect_to post_url(@post), :status => 301, :flash => { :updated_post_id => @post.id }
49
52
  # redirect_to { :action=>'atom' }, :alert => "Something serious happened"
50
53
  #
51
- # When using <tt>redirect_to :back</tt>, if there is no referrer,
52
- # RedirectBackError will be raised. You may specify some fallback
54
+ # When using <tt>redirect_to :back</tt>, if there is no referrer, RedirectBackError will be raised. You may specify some fallback
53
55
  # behavior for this case by rescuing RedirectBackError.
54
56
  def redirect_to(options = {}, response_status = {}) #:doc:
55
57
  raise ActionControllerError.new("Cannot redirect to nil!") if options.nil?
@@ -71,7 +71,7 @@ module ActionController
71
71
  end
72
72
 
73
73
  add :json do |json, options|
74
- json = ActiveSupport::JSON.encode(json, options) unless json.respond_to?(:to_str)
74
+ json = json.to_json(options) unless json.respond_to?(:to_str)
75
75
  json = "#{options[:callback]}(#{json})" unless options[:callback].blank?
76
76
  self.content_type ||= Mime::JSON
77
77
  self.response_body = json
@@ -161,6 +161,8 @@ module ActionController #:nodoc:
161
161
  display resource.errors, :status => :unprocessable_entity
162
162
  elsif post?
163
163
  display resource, :status => :created, :location => api_location
164
+ elsif has_empty_resource_definition?
165
+ display empty_resource, :status => :ok
164
166
  else
165
167
  head :ok
166
168
  end
@@ -221,5 +223,23 @@ module ActionController #:nodoc:
221
223
  def default_action
222
224
  @action ||= ACTIONS_FOR_VERBS[request.request_method_symbol]
223
225
  end
226
+
227
+ # Check whether resource needs a specific definition of empty resource to be valid
228
+ #
229
+ def has_empty_resource_definition?
230
+ respond_to?("empty_#{format}_resource")
231
+ end
232
+
233
+ # Delegate to proper empty resource method
234
+ #
235
+ def empty_resource
236
+ send("empty_#{format}_resource")
237
+ end
238
+
239
+ # Return a valid empty JSON resource
240
+ #
241
+ def empty_json_resource
242
+ "{}"
243
+ end
224
244
  end
225
245
  end
@@ -40,6 +40,13 @@ module ActionController
40
40
  ActiveSupport::Notifications.unsubscribe("!render_template.action_view")
41
41
  end
42
42
 
43
+ def process(*args)
44
+ @partials = Hash.new(0)
45
+ @templates = Hash.new(0)
46
+ @layouts = Hash.new(0)
47
+ super
48
+ end
49
+
43
50
  # Asserts that the request was rendered with the appropriate template file or partials.
44
51
  #
45
52
  # ==== Examples
@@ -38,18 +38,14 @@ module HTML #:nodoc:
38
38
  private
39
39
 
40
40
  def keys_to_strings(hash)
41
- hash.keys.inject({}) do |h,k|
42
- h[k.to_s] = hash[k]
43
- h
44
- end
41
+ Hash[hash.keys.map {|k| [k.to_s, hash[k]]}]
45
42
  end
46
43
 
47
44
  def keys_to_symbols(hash)
48
- hash.keys.inject({}) do |h,k|
45
+ Hash[hash.keys.map do |k|
49
46
  raise "illegal key #{k.inspect}" unless k.respond_to?(:to_sym)
50
- h[k.to_sym] = hash[k]
51
- h
52
- end
47
+ [k.to_sym, hash[k]]
48
+ end]
53
49
  end
54
50
  end
55
51
 
@@ -77,9 +73,7 @@ module HTML #:nodoc:
77
73
 
78
74
  # Return a textual representation of the node.
79
75
  def to_s
80
- s = ""
81
- @children.each { |child| s << child.to_s }
82
- s
76
+ @children.join()
83
77
  end
84
78
 
85
79
  # Return false (subclasses must override this to provide specific matching
@@ -4,6 +4,7 @@ require 'strscan'
4
4
 
5
5
  require 'active_support/core_ext/hash/indifferent_access'
6
6
  require 'active_support/core_ext/string/access'
7
+ require 'active_support/inflector'
7
8
  require 'action_dispatch/http/headers'
8
9
 
9
10
  module ActionDispatch
@@ -44,8 +45,24 @@ module ActionDispatch
44
45
  @env.key?(key)
45
46
  end
46
47
 
47
- HTTP_METHODS = %w(get head put post delete options)
48
- HTTP_METHOD_LOOKUP = HTTP_METHODS.inject({}) { |h, m| h[m] = h[m.upcase] = m.to_sym; h }
48
+ # List of HTTP request methods from the following RFCs:
49
+ # Hypertext Transfer Protocol -- HTTP/1.1 (http://www.ietf.org/rfc/rfc2616.txt)
50
+ # HTTP Extensions for Distributed Authoring -- WEBDAV (http://www.ietf.org/rfc/rfc2518.txt)
51
+ # Versioning Extensions to WebDAV (http://www.ietf.org/rfc/rfc3253.txt)
52
+ # Ordered Collections Protocol (WebDAV) (http://www.ietf.org/rfc/rfc3648.txt)
53
+ # Web Distributed Authoring and Versioning (WebDAV) Access Control Protocol (http://www.ietf.org/rfc/rfc3744.txt)
54
+ # Web Distributed Authoring and Versioning (WebDAV) SEARCH (http://www.ietf.org/rfc/rfc5323.txt)
55
+ # PATCH Method for HTTP (http://www.ietf.org/rfc/rfc5789.txt)
56
+ RFC2616 = %w(OPTIONS GET HEAD POST PUT DELETE TRACE CONNECT)
57
+ RFC2518 = %w(PROPFIND PROPPATCH MKCOL COPY MOVE LOCK UNLOCK)
58
+ RFC3253 = %w(VERSION-CONTROL REPORT CHECKOUT CHECKIN UNCHECKOUT MKWORKSPACE UPDATE LABEL MERGE BASELINE-CONTROL MKACTIVITY)
59
+ RFC3648 = %w(ORDERPATCH)
60
+ RFC3744 = %w(ACL)
61
+ RFC5323 = %w(SEARCH)
62
+ RFC5789 = %w(PATCH)
63
+
64
+ HTTP_METHODS = RFC2616 + RFC2518 + RFC3253 + RFC3648 + RFC3744 + RFC5323 + RFC5789
65
+ HTTP_METHOD_LOOKUP = Hash.new { |h, m| h[m] = m.underscore.to_sym if HTTP_METHODS.include?(m) }
49
66
 
50
67
  # Returns the HTTP \method that the application should see.
51
68
  # In the case where the \method was overridden by a middleware
@@ -4,27 +4,26 @@ require 'active_support/core_ext/object/blank'
4
4
  require 'active_support/core_ext/class/attribute_accessors'
5
5
 
6
6
  module ActionDispatch # :nodoc:
7
- # Represents an HTTP response generated by a controller action. One can use
8
- # an ActionDispatch::Response object to retrieve the current state
9
- # of the response, or customize the response. An Response object can
10
- # either represent a "real" HTTP response (i.e. one that is meant to be sent
11
- # back to the web browser) or a test response (i.e. one that is generated
12
- # from integration tests). See CgiResponse and TestResponse, respectively.
7
+ # Represents an HTTP response generated by a controller action. Use it to
8
+ # retrieve the current state of the response, or customize the response. It can
9
+ # either represent a real HTTP response (i.e. one that is meant to be sent
10
+ # back to the web browser) or a TestResponse (i.e. one that is generated
11
+ # from integration tests).
13
12
  #
14
- # Response is mostly a Ruby on Rails framework implement detail, and
13
+ # \Response is mostly a Ruby on \Rails framework implementation detail, and
15
14
  # should never be used directly in controllers. Controllers should use the
16
15
  # methods defined in ActionController::Base instead. For example, if you want
17
16
  # to set the HTTP response's content MIME type, then use
18
17
  # ActionControllerBase#headers instead of Response#headers.
19
18
  #
20
19
  # Nevertheless, integration tests may want to inspect controller responses in
21
- # more detail, and that's when Response can be useful for application
20
+ # more detail, and that's when \Response can be useful for application
22
21
  # developers. Integration test methods such as
23
22
  # ActionDispatch::Integration::Session#get and
24
23
  # ActionDispatch::Integration::Session#post return objects of type
25
- # TestResponse (which are of course also of type Response).
24
+ # TestResponse (which are of course also of type \Response).
26
25
  #
27
- # For example, the following demo integration "test" prints the body of the
26
+ # For example, the following demo integration test prints the body of the
28
27
  # controller response to the console:
29
28
  #
30
29
  # class DemoControllerTest < ActionDispatch::IntegrationTest
@@ -2,31 +2,27 @@ require 'active_support/core_ext/object/blank'
2
2
 
3
3
  module ActionDispatch
4
4
  module Http
5
- module UploadedFile
6
- def self.extended(object)
7
- object.class_eval do
8
- attr_accessor :original_path, :content_type
9
- alias_method :local_path, :path if method_defined?(:path)
10
- end
5
+ class UploadedFile
6
+ attr_accessor :original_filename, :content_type, :tempfile, :headers
7
+
8
+ def initialize(hash)
9
+ @original_filename = hash[:filename]
10
+ @content_type = hash[:type]
11
+ @headers = hash[:head]
12
+ @tempfile = hash[:tempfile]
13
+ raise(ArgumentError, ':tempfile is required') unless @tempfile
11
14
  end
12
15
 
13
- # Take the basename of the upload's original filename.
14
- # This handles the full Windows paths given by Internet Explorer
15
- # (and perhaps other broken user agents) without affecting
16
- # those which give the lone filename.
17
- # The Windows regexp is adapted from Perl's File::Basename.
18
- def original_filename
19
- unless defined? @original_filename
20
- @original_filename =
21
- unless original_path.blank?
22
- if original_path =~ /^(?:.*[:\\\/])?(.*)/m
23
- $1
24
- else
25
- File.basename original_path
26
- end
27
- end
28
- end
29
- @original_filename
16
+ def read(*args)
17
+ @tempfile.read(*args)
18
+ end
19
+
20
+ def rewind
21
+ @tempfile.rewind
22
+ end
23
+
24
+ def size
25
+ @tempfile.size
30
26
  end
31
27
  end
32
28
 
@@ -35,11 +31,7 @@ module ActionDispatch
35
31
  # file upload hash with UploadedFile objects
36
32
  def normalize_parameters(value)
37
33
  if Hash === value && value.has_key?(:tempfile)
38
- upload = value[:tempfile]
39
- upload.extend(UploadedFile)
40
- upload.original_path = value[:filename]
41
- upload.content_type = value[:type]
42
- upload
34
+ UploadedFile.new(value)
43
35
  else
44
36
  super
45
37
  end
@@ -47,4 +39,4 @@ module ActionDispatch
47
39
  private :normalize_parameters
48
40
  end
49
41
  end
50
- end
42
+ end
@@ -98,17 +98,19 @@ module ActionDispatch
98
98
  def self.build(request)
99
99
  secret = request.env[TOKEN_KEY]
100
100
  host = request.host
101
+ secure = request.ssl?
101
102
 
102
- new(secret, host).tap do |hash|
103
+ new(secret, host, secure).tap do |hash|
103
104
  hash.update(request.cookies)
104
105
  end
105
106
  end
106
107
 
107
- def initialize(secret = nil, host = nil)
108
+ def initialize(secret = nil, host = nil, secure = false)
108
109
  @secret = secret
109
110
  @set_cookies = {}
110
111
  @delete_cookies = {}
111
112
  @host = host
113
+ @secure = secure
112
114
 
113
115
  super()
114
116
  end
@@ -193,9 +195,15 @@ module ActionDispatch
193
195
  end
194
196
 
195
197
  def write(headers)
196
- @set_cookies.each { |k, v| ::Rack::Utils.set_cookie_header!(headers, k, v) }
198
+ @set_cookies.each { |k, v| ::Rack::Utils.set_cookie_header!(headers, k, v) if write_cookie?(v) }
197
199
  @delete_cookies.each { |k, v| ::Rack::Utils.delete_cookie_header!(headers, k, v) }
198
200
  end
201
+
202
+ private
203
+
204
+ def write_cookie?(cookie)
205
+ @secure || !cookie[:secure] || defined?(Rails.env) && Rails.env.development?
206
+ end
199
207
  end
200
208
 
201
209
  class PermanentCookieJar < CookieJar #:nodoc: