actionpack 1.12.5 → 1.13.0
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.
- data/CHANGELOG +517 -15
- data/MIT-LICENSE +1 -1
- data/README +18 -20
- data/Rakefile +7 -4
- data/examples/address_book_controller.rb +3 -3
- data/examples/blog_controller.cgi +3 -3
- data/examples/debate_controller.cgi +5 -5
- data/lib/action_controller.rb +2 -2
- data/lib/action_controller/assertions.rb +73 -311
- data/lib/action_controller/{deprecated_assertions.rb → assertions/deprecated_assertions.rb} +32 -8
- data/lib/action_controller/assertions/dom_assertions.rb +25 -0
- data/lib/action_controller/assertions/model_assertions.rb +12 -0
- data/lib/action_controller/assertions/response_assertions.rb +140 -0
- data/lib/action_controller/assertions/routing_assertions.rb +82 -0
- data/lib/action_controller/assertions/selector_assertions.rb +571 -0
- data/lib/action_controller/assertions/tag_assertions.rb +117 -0
- data/lib/action_controller/base.rb +334 -163
- data/lib/action_controller/benchmarking.rb +3 -6
- data/lib/action_controller/caching.rb +83 -22
- data/lib/action_controller/cgi_ext/cgi_ext.rb +0 -7
- data/lib/action_controller/cgi_ext/cgi_methods.rb +167 -173
- data/lib/action_controller/cgi_ext/raw_post_data_fix.rb +43 -22
- data/lib/action_controller/cgi_process.rb +50 -27
- data/lib/action_controller/components.rb +21 -25
- data/lib/action_controller/cookies.rb +10 -9
- data/lib/action_controller/{dependencies.rb → deprecated_dependencies.rb} +9 -27
- data/lib/action_controller/filters.rb +448 -225
- data/lib/action_controller/flash.rb +24 -20
- data/lib/action_controller/helpers.rb +2 -5
- data/lib/action_controller/integration.rb +40 -16
- data/lib/action_controller/layout.rb +11 -8
- data/lib/action_controller/macros/auto_complete.rb +3 -2
- data/lib/action_controller/macros/in_place_editing.rb +3 -2
- data/lib/action_controller/mime_responds.rb +41 -29
- data/lib/action_controller/mime_type.rb +68 -10
- data/lib/action_controller/pagination.rb +4 -3
- data/lib/action_controller/request.rb +22 -14
- data/lib/action_controller/rescue.rb +25 -22
- data/lib/action_controller/resources.rb +302 -0
- data/lib/action_controller/response.rb +20 -2
- data/lib/action_controller/response.rb.rej +17 -0
- data/lib/action_controller/routing.rb +1165 -567
- data/lib/action_controller/scaffolding.rb +30 -31
- data/lib/action_controller/session/active_record_store.rb +2 -0
- data/lib/action_controller/session/drb_store.rb +4 -0
- data/lib/action_controller/session/mem_cache_store.rb +4 -0
- data/lib/action_controller/session_management.rb +6 -9
- data/lib/action_controller/status_codes.rb +89 -0
- data/lib/action_controller/streaming.rb +6 -15
- data/lib/action_controller/templates/rescues/_request_and_response.rhtml +5 -5
- data/lib/action_controller/templates/rescues/diagnostics.rhtml +2 -2
- data/lib/action_controller/templates/rescues/routing_error.rhtml +4 -4
- data/lib/action_controller/templates/rescues/template_error.rhtml +1 -1
- data/lib/action_controller/templates/scaffolds/list.rhtml +1 -1
- data/lib/action_controller/test_process.rb +52 -30
- data/lib/action_controller/url_rewriter.rb +63 -29
- data/lib/action_controller/vendor/html-scanner/html/document.rb +1 -0
- data/lib/action_controller/vendor/html-scanner/html/node.rb +3 -4
- data/lib/action_controller/vendor/html-scanner/html/selector.rb +822 -0
- data/lib/action_controller/verification.rb +22 -11
- data/lib/action_pack.rb +1 -1
- data/lib/action_pack/version.rb +2 -2
- data/lib/action_view.rb +1 -1
- data/lib/action_view/base.rb +46 -43
- data/lib/action_view/compiled_templates.rb +1 -1
- data/lib/action_view/helpers/active_record_helper.rb +54 -17
- data/lib/action_view/helpers/asset_tag_helper.rb +97 -46
- data/lib/action_view/helpers/capture_helper.rb +1 -1
- data/lib/action_view/helpers/date_helper.rb +258 -136
- data/lib/action_view/helpers/debug_helper.rb +1 -1
- data/lib/action_view/helpers/deprecated_helper.rb +34 -0
- data/lib/action_view/helpers/form_helper.rb +75 -35
- data/lib/action_view/helpers/form_options_helper.rb +7 -5
- data/lib/action_view/helpers/form_tag_helper.rb +44 -6
- data/lib/action_view/helpers/java_script_macros_helper.rb +59 -46
- data/lib/action_view/helpers/javascript_helper.rb +71 -10
- data/lib/action_view/helpers/javascripts/controls.js +41 -23
- data/lib/action_view/helpers/javascripts/dragdrop.js +105 -76
- data/lib/action_view/helpers/javascripts/effects.js +293 -163
- data/lib/action_view/helpers/javascripts/prototype.js +897 -389
- data/lib/action_view/helpers/javascripts/prototype.js.rej +561 -0
- data/lib/action_view/helpers/number_helper.rb +111 -65
- data/lib/action_view/helpers/prototype_helper.rb +84 -109
- data/lib/action_view/helpers/scriptaculous_helper.rb +5 -0
- data/lib/action_view/helpers/tag_helper.rb +69 -16
- data/lib/action_view/helpers/text_helper.rb +149 -112
- data/lib/action_view/helpers/url_helper.rb +200 -107
- data/lib/action_view/template_error.rb +66 -42
- data/test/abstract_unit.rb +4 -2
- data/test/active_record_unit.rb +84 -56
- data/test/activerecord/active_record_assertions_test.rb +26 -18
- data/test/activerecord/active_record_store_test.rb +4 -36
- data/test/activerecord/pagination_test.rb +1 -6
- data/test/controller/action_pack_assertions_test.rb +230 -113
- data/test/controller/addresses_render_test.rb +2 -6
- data/test/controller/assert_select_test.rb +576 -0
- data/test/controller/base_test.rb +73 -3
- data/test/controller/caching_test.rb +228 -0
- data/test/controller/capture_test.rb +12 -10
- data/test/controller/cgi_test.rb +89 -12
- data/test/controller/components_test.rb +24 -2
- data/test/controller/content_type_test.rb +139 -0
- data/test/controller/controller_fixtures/app/controllers/admin/user_controller.rb +0 -0
- data/test/controller/controller_fixtures/app/controllers/user_controller.rb +0 -0
- data/test/controller/controller_fixtures/vendor/plugins/bad_plugin/lib/plugin_controller.rb +0 -0
- data/test/controller/cookie_test.rb +33 -25
- data/test/controller/deprecated_instance_variables_test.rb +48 -0
- data/test/controller/deprecation/deprecated_base_methods_test.rb +60 -0
- data/test/controller/fake_controllers.rb +0 -1
- data/test/controller/filters_test.rb +301 -16
- data/test/controller/flash_test.rb +19 -2
- data/test/controller/helper_test.rb +2 -2
- data/test/controller/integration_test.rb +154 -0
- data/test/controller/layout_test.rb +115 -1
- data/test/controller/mime_responds_test.rb +94 -0
- data/test/controller/mime_type_test.rb +9 -0
- data/test/controller/new_render_test.rb +161 -11
- data/test/controller/raw_post_test.rb +52 -15
- data/test/controller/redirect_test.rb +27 -14
- data/test/controller/render_test.rb +76 -29
- data/test/controller/request_test.rb +55 -4
- data/test/controller/resources_test.rb +274 -0
- data/test/controller/routing_test.rb +1533 -824
- data/test/controller/selector_test.rb +628 -0
- data/test/controller/send_file_test.rb +9 -1
- data/test/controller/session_management_test.rb +51 -0
- data/test/controller/test_test.rb +113 -29
- data/test/controller/url_rewriter_test.rb +86 -17
- data/test/controller/verification_test.rb +19 -17
- data/test/controller/webservice_test.rb +0 -7
- data/test/fixtures/content_type/render_default_content_types_for_respond_to.rhtml +1 -0
- data/test/fixtures/content_type/render_default_for_rhtml.rhtml +1 -0
- data/test/fixtures/content_type/render_default_for_rjs.rjs +1 -0
- data/test/fixtures/content_type/render_default_for_rxml.rxml +1 -0
- data/test/fixtures/deprecated_instance_variables/_cookies_ivar.rhtml +1 -0
- data/test/fixtures/deprecated_instance_variables/_cookies_method.rhtml +1 -0
- data/test/fixtures/deprecated_instance_variables/_flash_ivar.rhtml +1 -0
- data/test/fixtures/deprecated_instance_variables/_flash_method.rhtml +1 -0
- data/test/fixtures/deprecated_instance_variables/_headers_ivar.rhtml +1 -0
- data/test/fixtures/deprecated_instance_variables/_headers_method.rhtml +1 -0
- data/test/fixtures/deprecated_instance_variables/_params_ivar.rhtml +1 -0
- data/test/fixtures/deprecated_instance_variables/_params_method.rhtml +1 -0
- data/test/fixtures/deprecated_instance_variables/_request_ivar.rhtml +1 -0
- data/test/fixtures/deprecated_instance_variables/_request_method.rhtml +1 -0
- data/test/fixtures/deprecated_instance_variables/_response_ivar.rhtml +1 -0
- data/test/fixtures/deprecated_instance_variables/_response_method.rhtml +1 -0
- data/test/fixtures/deprecated_instance_variables/_session_ivar.rhtml +1 -0
- data/test/fixtures/deprecated_instance_variables/_session_method.rhtml +1 -0
- data/test/fixtures/multipart/binary_file +0 -0
- data/test/fixtures/public/javascripts/application.js +1 -0
- data/test/fixtures/test/_hello.rxml +1 -0
- data/test/fixtures/test/hello_world_container.rxml +3 -0
- data/test/fixtures/topic.rb +2 -2
- data/test/template/active_record_helper_test.rb +83 -12
- data/test/template/asset_tag_helper_test.rb +75 -95
- data/test/template/compiled_templates_test.rb +1 -0
- data/test/template/date_helper_test.rb +873 -181
- data/test/template/deprecated_helper_test.rb +36 -0
- data/test/template/deprecated_instance_variables_test.rb +43 -0
- data/test/template/form_helper_test.rb +77 -1
- data/test/template/form_options_helper_test.rb +4 -0
- data/test/template/form_tag_helper_test.rb +66 -2
- data/test/template/java_script_macros_helper_test.rb +4 -1
- data/test/template/javascript_helper_test.rb +29 -0
- data/test/template/number_helper_test.rb +63 -27
- data/test/template/prototype_helper_test.rb +77 -34
- data/test/template/tag_helper_test.rb +34 -6
- data/test/template/text_helper_test.rb +69 -34
- data/test/template/url_helper_test.rb +168 -16
- data/test/testing_sandbox.rb +7 -22
- metadata +66 -20
- data/filler.txt +0 -50
- data/lib/action_controller/code_generation.rb +0 -235
- data/lib/action_controller/vendor/xml_simple.rb +0 -1019
- data/test/controller/caching_filestore.rb +0 -74
- data/test/fixtures/application_root/app/controllers/a_class_that_contains_a_controller/poorly_placed_controller.rb +0 -7
- data/test/fixtures/application_root/app/controllers/module_that_holds_controllers/nested_controller.rb +0 -3
- data/test/fixtures/application_root/app/models/a_class_that_contains_a_controller.rb +0 -7
- data/test/fixtures/dont_load.rb +0 -3
@@ -1,5 +1,18 @@
|
|
1
1
|
module Mime
|
2
|
-
|
2
|
+
# Encapsulates the notion of a mime type. Can be used at render time, for example, with:
|
3
|
+
#
|
4
|
+
# class PostsController < ActionController::Base
|
5
|
+
# def show
|
6
|
+
# @post = Post.find(params[:id])
|
7
|
+
#
|
8
|
+
# respond_to do |format|
|
9
|
+
# format.html
|
10
|
+
# format.ics { render :text => post.to_ics, :mime_type => Mime::Type["text/calendar"] }
|
11
|
+
# format.xml { render :xml => @people.to_xml }
|
12
|
+
# end
|
13
|
+
# end
|
14
|
+
# end
|
15
|
+
class Type
|
3
16
|
# A simple helper class used in parsing the accept header
|
4
17
|
class AcceptItem #:nodoc:
|
5
18
|
attr_accessor :order, :name, :q
|
@@ -31,14 +44,20 @@ module Mime
|
|
31
44
|
LOOKUP[string]
|
32
45
|
end
|
33
46
|
|
47
|
+
def register(string, symbol, synonyms = [])
|
48
|
+
Mime.send :const_set, symbol.to_s.upcase, Type.new(string, symbol, synonyms)
|
49
|
+
SET << Mime.send(:const_get, symbol.to_s.upcase)
|
50
|
+
LOOKUP[string] = EXTENSION_LOOKUP[symbol.to_s] = SET.last
|
51
|
+
end
|
52
|
+
|
34
53
|
def parse(accept_header)
|
35
54
|
# keep track of creation order to keep the subsequent sort stable
|
36
55
|
index = 0
|
37
|
-
list = accept_header.split(/,/).
|
38
|
-
|
56
|
+
list = accept_header.split(/,/).map! do |i|
|
57
|
+
AcceptItem.new(index += 1, *i.split(/;\s*q=/))
|
58
|
+
end.sort!
|
39
59
|
|
40
60
|
# Take care of the broken text/xml entry by renaming or deleting it
|
41
|
-
|
42
61
|
text_xml = list.index("text/xml")
|
43
62
|
app_xml = list.index("application/xml")
|
44
63
|
|
@@ -112,31 +131,70 @@ module Mime
|
|
112
131
|
end
|
113
132
|
|
114
133
|
ALL = Type.new "*/*", :all
|
134
|
+
TEXT = Type.new "text/plain", :text
|
115
135
|
HTML = Type.new "text/html", :html, %w( application/xhtml+xml )
|
116
136
|
JS = Type.new "text/javascript", :js, %w( application/javascript application/x-javascript )
|
137
|
+
ICS = Type.new "text/calendar", :ics
|
138
|
+
CSV = Type.new "text/csv", :csv
|
117
139
|
XML = Type.new "application/xml", :xml, %w( text/xml application/x-xml )
|
118
140
|
RSS = Type.new "application/rss+xml", :rss
|
119
141
|
ATOM = Type.new "application/atom+xml", :atom
|
120
142
|
YAML = Type.new "application/x-yaml", :yaml, %w( text/yaml )
|
143
|
+
JSON = Type.new "application/json", :json, %w( text/x-json )
|
144
|
+
|
145
|
+
SET = [ ALL, TEXT, HTML, JS, ICS, XML, RSS, ATOM, YAML, JSON ]
|
121
146
|
|
122
|
-
LOOKUP = Hash.new { |h, k| h[k] = Type.new(k) }
|
147
|
+
LOOKUP = Hash.new { |h, k| h[k] = Type.new(k) unless k == "" }
|
123
148
|
|
124
149
|
LOOKUP["*/*"] = ALL
|
125
150
|
|
151
|
+
LOOKUP["text/plain"] = TEXT
|
152
|
+
|
126
153
|
LOOKUP["text/html"] = HTML
|
127
154
|
LOOKUP["application/xhtml+xml"] = HTML
|
128
155
|
|
129
|
-
LOOKUP["application/xml"] = XML
|
130
|
-
LOOKUP["text/xml"] = XML
|
131
|
-
LOOKUP["application/x-xml"] = XML
|
132
|
-
|
133
156
|
LOOKUP["text/javascript"] = JS
|
134
157
|
LOOKUP["application/javascript"] = JS
|
135
158
|
LOOKUP["application/x-javascript"] = JS
|
136
159
|
|
160
|
+
LOOKUP["text/calendar"] = ICS
|
161
|
+
|
162
|
+
LOOKUP["text/csv"] = CSV
|
163
|
+
|
164
|
+
LOOKUP["application/xml"] = XML
|
165
|
+
LOOKUP["text/xml"] = XML
|
166
|
+
LOOKUP["application/x-xml"] = XML
|
167
|
+
|
137
168
|
LOOKUP["text/yaml"] = YAML
|
138
169
|
LOOKUP["application/x-yaml"] = YAML
|
139
170
|
|
140
171
|
LOOKUP["application/rss+xml"] = RSS
|
141
172
|
LOOKUP["application/atom+xml"] = ATOM
|
142
|
-
|
173
|
+
|
174
|
+
LOOKUP["application/json"] = JSON
|
175
|
+
LOOKUP["text/x-json"] = JSON
|
176
|
+
|
177
|
+
|
178
|
+
EXTENSION_LOOKUP = Hash.new { |h, k| h[k] = Type.new(k) unless k == "" }
|
179
|
+
|
180
|
+
EXTENSION_LOOKUP["html"] = HTML
|
181
|
+
EXTENSION_LOOKUP["xhtml"] = HTML
|
182
|
+
|
183
|
+
EXTENSION_LOOKUP["txt"] = TEXT
|
184
|
+
|
185
|
+
EXTENSION_LOOKUP["xml"] = XML
|
186
|
+
|
187
|
+
EXTENSION_LOOKUP["js"] = JS
|
188
|
+
|
189
|
+
EXTENSION_LOOKUP["ics"] = ICS
|
190
|
+
|
191
|
+
EXTENSION_LOOKUP["csv"] = CSV
|
192
|
+
|
193
|
+
EXTENSION_LOOKUP["yml"] = YAML
|
194
|
+
EXTENSION_LOOKUP["yaml"] = YAML
|
195
|
+
|
196
|
+
EXTENSION_LOOKUP["rss"] = RSS
|
197
|
+
EXTENSION_LOOKUP["atom"] = ATOM
|
198
|
+
|
199
|
+
EXTENSION_LOOKUP["json"] = JSON
|
200
|
+
end
|
@@ -1,6 +1,8 @@
|
|
1
1
|
module ActionController
|
2
2
|
# === Action Pack pagination for Active Record collections
|
3
3
|
#
|
4
|
+
# DEPRECATION WARNING: Pagination will be separated into its own plugin with Rails 2.0.
|
5
|
+
#
|
4
6
|
# The Pagination module aids in the process of paging large collections of
|
5
7
|
# Active Record objects. It offers macro-style automatic fetching of your
|
6
8
|
# model for multiple views, or explicit fetching for single actions. And if
|
@@ -104,8 +106,7 @@ module ActionController
|
|
104
106
|
# ClassMethods#paginate.
|
105
107
|
#
|
106
108
|
# +options+ are:
|
107
|
-
# <tt>:singular_name</tt>:: the singular name to use, if it can't be inferred by
|
108
|
-
# singularizing the collection name
|
109
|
+
# <tt>:singular_name</tt>:: the singular name to use, if it can't be inferred by singularizing the collection name
|
109
110
|
# <tt>:class_name</tt>:: the class name to use, if it can't be inferred by
|
110
111
|
# camelizing the singular name
|
111
112
|
# <tt>:per_page</tt>:: the maximum number of items to include in a
|
@@ -192,7 +193,7 @@ module ActionController
|
|
192
193
|
|
193
194
|
def paginator_and_collection_for(collection_id, options) #:nodoc:
|
194
195
|
klass = options[:class_name].constantize
|
195
|
-
page =
|
196
|
+
page = params[options[:parameter]]
|
196
197
|
count = count_collection_for_pagination(klass, options)
|
197
198
|
paginator = Paginator.new(self, count, options[:per_page], page)
|
198
199
|
collection = find_collection_for_pagination(klass, options, paginator)
|
@@ -13,12 +13,18 @@ module ActionController
|
|
13
13
|
@parameters ||= request_parameters.update(query_parameters).update(path_parameters).with_indifferent_access
|
14
14
|
end
|
15
15
|
|
16
|
-
# Returns the HTTP request method as a lowercase symbol (:get, for example)
|
16
|
+
# Returns the HTTP request method as a lowercase symbol (:get, for example). Note, HEAD is returned as :get
|
17
|
+
# since the two are supposedly to be functionaly equivilent for all purposes except that HEAD won't return a response
|
18
|
+
# body (which Rails also takes care of elsewhere).
|
17
19
|
def method
|
18
|
-
@request_method ||= @env['REQUEST_METHOD']
|
20
|
+
@request_method ||= (!parameters[:_method].blank? && @env['REQUEST_METHOD'] == 'POST') ?
|
21
|
+
parameters[:_method].to_s.downcase.to_sym :
|
22
|
+
@env['REQUEST_METHOD'].downcase.to_sym
|
23
|
+
|
24
|
+
@request_method == :head ? :get : @request_method
|
19
25
|
end
|
20
26
|
|
21
|
-
# Is this a GET request? Equivalent to request.method == :get
|
27
|
+
# Is this a GET (or HEAD) request? Equivalent to request.method == :get
|
22
28
|
def get?
|
23
29
|
method == :get
|
24
30
|
end
|
@@ -38,9 +44,10 @@ module ActionController
|
|
38
44
|
method == :delete
|
39
45
|
end
|
40
46
|
|
41
|
-
# Is this a HEAD request?
|
47
|
+
# Is this a HEAD request? HEAD is mapped as :get for request.method, so here we ask the
|
48
|
+
# REQUEST_METHOD header directly. Thus, for head, both get? and head? will return true.
|
42
49
|
def head?
|
43
|
-
|
50
|
+
@env['REQUEST_METHOD'].downcase.to_sym == :head
|
44
51
|
end
|
45
52
|
|
46
53
|
# Determine whether the body of a HTTP call is URL-encoded (default)
|
@@ -128,19 +135,21 @@ module ActionController
|
|
128
135
|
@env['RAW_POST_DATA']
|
129
136
|
end
|
130
137
|
|
131
|
-
#
|
132
|
-
#
|
138
|
+
# Return the request URI, accounting for server idiosyncracies.
|
139
|
+
# WEBrick includes the full URL. IIS leaves REQUEST_URI blank.
|
133
140
|
def request_uri
|
134
141
|
if uri = @env['REQUEST_URI']
|
135
|
-
|
136
|
-
|
142
|
+
# Remove domain, which webrick puts into the request_uri.
|
143
|
+
(%r{^\w+\://[^/]+(/.*|$)$} =~ uri) ? $1 : uri
|
144
|
+
else
|
145
|
+
# Construct IIS missing REQUEST_URI from SCRIPT_NAME and PATH_INFO.
|
137
146
|
script_filename = @env['SCRIPT_NAME'].to_s.match(%r{[^/]+$})
|
138
147
|
uri = @env['PATH_INFO']
|
139
148
|
uri = uri.sub(/#{script_filename}\//, '') unless script_filename.nil?
|
140
149
|
unless (env_qs = @env['QUERY_STRING']).nil? || env_qs.empty?
|
141
150
|
uri << '?' << env_qs
|
142
151
|
end
|
143
|
-
uri
|
152
|
+
@env['REQUEST_URI'] = uri
|
144
153
|
end
|
145
154
|
end
|
146
155
|
|
@@ -159,11 +168,10 @@ module ActionController
|
|
159
168
|
path = (uri = request_uri) ? uri.split('?').first : ''
|
160
169
|
|
161
170
|
# Cut off the path to the installation directory if given
|
162
|
-
|
163
|
-
path
|
164
|
-
path || ''
|
171
|
+
path.sub!(%r/^#{relative_url_root}/, '')
|
172
|
+
path || ''
|
165
173
|
end
|
166
|
-
|
174
|
+
|
167
175
|
# Returns the path minus the web server relative installation directory.
|
168
176
|
# This can be set with the environment variable RAILS_RELATIVE_URL_ROOT.
|
169
177
|
# It can be automatically extracted for Apache setups. If the server is not
|
@@ -6,12 +6,10 @@ module ActionController #:nodoc:
|
|
6
6
|
#
|
7
7
|
# You can tailor the rescuing behavior and appearance by overwriting the following two stub methods.
|
8
8
|
module Rescue
|
9
|
-
def self.
|
10
|
-
super
|
9
|
+
def self.included(base) #:nodoc:
|
11
10
|
base.extend(ClassMethods)
|
12
11
|
base.class_eval do
|
13
|
-
|
14
|
-
alias_method :perform_action, :perform_action_with_rescue
|
12
|
+
alias_method_chain :perform_action, :rescue
|
15
13
|
end
|
16
14
|
end
|
17
15
|
|
@@ -36,23 +34,26 @@ module ActionController #:nodoc:
|
|
36
34
|
|
37
35
|
# Overwrite to implement custom logging of errors. By default logs as fatal.
|
38
36
|
def log_error(exception) #:doc:
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
37
|
+
ActiveSupport::Deprecation.silence do
|
38
|
+
if ActionView::TemplateError === exception
|
39
|
+
logger.fatal(exception.to_s)
|
40
|
+
else
|
41
|
+
logger.fatal(
|
42
|
+
"\n\n#{exception.class} (#{exception.message}):\n " +
|
43
|
+
clean_backtrace(exception).join("\n ") +
|
44
|
+
"\n\n"
|
45
|
+
)
|
46
|
+
end
|
47
47
|
end
|
48
48
|
end
|
49
49
|
|
50
50
|
# Overwrite to implement public exception handling (for requests answering false to <tt>local_request?</tt>).
|
51
51
|
def rescue_action_in_public(exception) #:doc:
|
52
52
|
case exception
|
53
|
-
when RoutingError, UnknownAction
|
53
|
+
when RoutingError, UnknownAction
|
54
54
|
render_text(IO.read(File.join(RAILS_ROOT, 'public', '404.html')), "404 Not Found")
|
55
|
-
else
|
55
|
+
else
|
56
|
+
render_text(IO.read(File.join(RAILS_ROOT, 'public', '500.html')), "500 Internal Error")
|
56
57
|
end
|
57
58
|
end
|
58
59
|
|
@@ -60,19 +61,19 @@ module ActionController #:nodoc:
|
|
60
61
|
# the remote IP being 127.0.0.1. For example, this could include the IP of the developer machine when debugging
|
61
62
|
# remotely.
|
62
63
|
def local_request? #:doc:
|
63
|
-
[
|
64
|
+
[request.remote_addr, request.remote_ip] == ["127.0.0.1"] * 2
|
64
65
|
end
|
65
66
|
|
66
67
|
# Renders a detailed diagnostics screen on action exceptions.
|
67
68
|
def rescue_action_locally(exception)
|
68
69
|
add_variables_to_assigns
|
69
70
|
@template.instance_variable_set("@exception", exception)
|
70
|
-
@template.instance_variable_set("@rescues_path", File.dirname(
|
71
|
+
@template.instance_variable_set("@rescues_path", File.dirname(rescues_path("stub")))
|
71
72
|
@template.send(:assign_variables_from_controller)
|
72
73
|
|
73
74
|
@template.instance_variable_set("@contents", @template.render_file(template_path_for_local_rescue(exception), false))
|
74
75
|
|
75
|
-
|
76
|
+
response.content_type = Mime::HTML
|
76
77
|
render_file(rescues_path("layout"), response_code_for_rescue(exception))
|
77
78
|
end
|
78
79
|
|
@@ -80,8 +81,8 @@ module ActionController #:nodoc:
|
|
80
81
|
def perform_action_with_rescue #:nodoc:
|
81
82
|
begin
|
82
83
|
perform_action_without_rescue
|
83
|
-
rescue
|
84
|
-
if defined?(Breakpoint) &&
|
84
|
+
rescue Exception => exception # errors from action performed
|
85
|
+
if defined?(Breakpoint) && params["BP-RETRY"]
|
85
86
|
msg = exception.backtrace.first
|
86
87
|
if md = /^(.+?):(\d+)(?::in `(.+)')?$/.match(msg) then
|
87
88
|
origin_file, origin_line = md[1], md[2].to_i
|
@@ -89,7 +90,7 @@ module ActionController #:nodoc:
|
|
89
90
|
set_trace_func(lambda do |type, file, line, method, context, klass|
|
90
91
|
if file == origin_file and line == origin_line then
|
91
92
|
set_trace_func(nil)
|
92
|
-
|
93
|
+
params["BP-RETRY"] = false
|
93
94
|
|
94
95
|
callstack = caller
|
95
96
|
callstack.slice!(0) if callstack.first["rescue.rb"]
|
@@ -127,8 +128,10 @@ module ActionController #:nodoc:
|
|
127
128
|
|
128
129
|
def response_code_for_rescue(exception)
|
129
130
|
case exception
|
130
|
-
when UnknownAction, RoutingError
|
131
|
-
|
131
|
+
when UnknownAction, RoutingError
|
132
|
+
"404 Page Not Found"
|
133
|
+
else
|
134
|
+
"500 Internal Error"
|
132
135
|
end
|
133
136
|
end
|
134
137
|
|
@@ -0,0 +1,302 @@
|
|
1
|
+
module ActionController
|
2
|
+
module Resources
|
3
|
+
class Resource #:nodoc:
|
4
|
+
attr_reader :collection_methods, :member_methods, :new_methods
|
5
|
+
attr_reader :path_prefix, :name_prefix
|
6
|
+
attr_reader :plural, :singular
|
7
|
+
attr_reader :options
|
8
|
+
|
9
|
+
def initialize(entities, options)
|
10
|
+
@plural = entities
|
11
|
+
@singular = options[:singular] || plural.to_s.singularize
|
12
|
+
|
13
|
+
@options = options
|
14
|
+
|
15
|
+
arrange_actions
|
16
|
+
add_default_actions
|
17
|
+
set_prefixes
|
18
|
+
end
|
19
|
+
|
20
|
+
def controller
|
21
|
+
(options[:controller] || plural).to_s
|
22
|
+
end
|
23
|
+
|
24
|
+
def path
|
25
|
+
"#{path_prefix}/#{plural}"
|
26
|
+
end
|
27
|
+
|
28
|
+
def new_path
|
29
|
+
"#{path}/new"
|
30
|
+
end
|
31
|
+
|
32
|
+
def member_path
|
33
|
+
"#{path}/:id"
|
34
|
+
end
|
35
|
+
|
36
|
+
def nesting_path_prefix
|
37
|
+
"#{path}/:#{singular}_id"
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
def arrange_actions
|
42
|
+
@collection_methods = arrange_actions_by_methods(options.delete(:collection))
|
43
|
+
@member_methods = arrange_actions_by_methods(options.delete(:member))
|
44
|
+
@new_methods = arrange_actions_by_methods(options.delete(:new))
|
45
|
+
end
|
46
|
+
|
47
|
+
def add_default_actions
|
48
|
+
add_default_action(member_methods, :get, :edit)
|
49
|
+
add_default_action(new_methods, :get, :new)
|
50
|
+
end
|
51
|
+
|
52
|
+
def set_prefixes
|
53
|
+
@path_prefix = options.delete(:path_prefix)
|
54
|
+
@name_prefix = options.delete(:name_prefix)
|
55
|
+
end
|
56
|
+
|
57
|
+
def arrange_actions_by_methods(actions)
|
58
|
+
(actions || {}).inject({}) do |flipped_hash, (key, value)|
|
59
|
+
(flipped_hash[value] ||= []) << key
|
60
|
+
flipped_hash
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def add_default_action(collection, method, action)
|
65
|
+
(collection[method] ||= []).unshift(action)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
# Creates named routes for implementing verb-oriented controllers. This is
|
70
|
+
# useful for implementing REST API's, where a single resource has different
|
71
|
+
# behavior based on the HTTP verb (method) used to access it.
|
72
|
+
#
|
73
|
+
# Example:
|
74
|
+
#
|
75
|
+
# map.resources :messages
|
76
|
+
#
|
77
|
+
# class MessagesController < ActionController::Base
|
78
|
+
# # GET messages_url
|
79
|
+
# def index
|
80
|
+
# # return all messages
|
81
|
+
# end
|
82
|
+
#
|
83
|
+
# # GET new_message_url
|
84
|
+
# def new
|
85
|
+
# # return an HTML form for describing a new message
|
86
|
+
# end
|
87
|
+
#
|
88
|
+
# # POST messages_url
|
89
|
+
# def create
|
90
|
+
# # create a new message
|
91
|
+
# end
|
92
|
+
#
|
93
|
+
# # GET message_url(:id => 1)
|
94
|
+
# def show
|
95
|
+
# # find and return a specific message
|
96
|
+
# end
|
97
|
+
#
|
98
|
+
# # GET edit_message_url(:id => 1)
|
99
|
+
# def edit
|
100
|
+
# # return an HTML form for editing a specific message
|
101
|
+
# end
|
102
|
+
#
|
103
|
+
# # PUT message_url(:id => 1)
|
104
|
+
# def update
|
105
|
+
# # find and update a specific message
|
106
|
+
# end
|
107
|
+
#
|
108
|
+
# # DELETE message_url(:id => 1)
|
109
|
+
# def destroy
|
110
|
+
# # delete a specific message
|
111
|
+
# end
|
112
|
+
# end
|
113
|
+
#
|
114
|
+
# The #resources method sets HTTP method restrictions on the routes it generates. For example, making an
|
115
|
+
# HTTP POST on <tt>new_message_url</tt> will raise a RoutingError exception. The default route in
|
116
|
+
# <tt>config/routes.rb</tt> overrides this and allows invalid HTTP methods for resource routes.
|
117
|
+
#
|
118
|
+
# Along with the routes themselves, #resources generates named routes for use in
|
119
|
+
# controllers and views. <tt>map.resources :messages</tt> produces the following named routes and helpers:
|
120
|
+
#
|
121
|
+
# Named Route Helpers
|
122
|
+
# messages messages_url, hash_for_messages_url,
|
123
|
+
# messages_path, hash_for_messages_path
|
124
|
+
# message message_url(id), hash_for_message_url(id),
|
125
|
+
# message_path(id), hash_for_message_path(id)
|
126
|
+
# new_message new_message_url, hash_for_new_message_url,
|
127
|
+
# new_message_path, hash_for_new_message_path
|
128
|
+
# edit_message edit_message_url(id), hash_for_edit_message_url(id),
|
129
|
+
# edit_message_path(id), hash_for_edit_message_path(id)
|
130
|
+
#
|
131
|
+
# You can use these helpers instead of #url_for or methods that take #url_for parameters:
|
132
|
+
#
|
133
|
+
# redirect_to :controller => 'messages', :action => 'index'
|
134
|
+
# # becomes
|
135
|
+
# redirect_to messages_url
|
136
|
+
#
|
137
|
+
# <%= link_to "edit this message", :controller => 'messages', :action => 'edit', :id => @message.id %>
|
138
|
+
# # becomes
|
139
|
+
# <%= link_to "edit this message", edit_message_url(@message) # calls @message.id automatically
|
140
|
+
#
|
141
|
+
# Since web browsers don't support the PUT and DELETE verbs, you will need to add a parameter '_method' to your
|
142
|
+
# form tags. The form helpers make this a little easier. For an update form with a <tt>@message</tt> object:
|
143
|
+
#
|
144
|
+
# <%= form_tag message_path(@message), :method => :put %>
|
145
|
+
#
|
146
|
+
# or
|
147
|
+
#
|
148
|
+
# <% form_for :message, @message, message_path(@message), :html => {:method => :put} do |f| %>
|
149
|
+
#
|
150
|
+
# The #resources method accepts various options, too, to customize the resulting
|
151
|
+
# routes:
|
152
|
+
# * <tt>:controller</tt> -- specify the controller name for the routes.
|
153
|
+
# * <tt>:singular</tt> -- specify the singular name used in the member routes.
|
154
|
+
# * <tt>:path_prefix</tt> -- set a prefix to the routes with required route variables.
|
155
|
+
# Weblog comments usually belong to a post, so you might use resources like:
|
156
|
+
#
|
157
|
+
# map.resources :articles
|
158
|
+
# map.resources :comments, :path_prefix => '/articles/:article_id'
|
159
|
+
#
|
160
|
+
# You can nest resources calls to set this automatically:
|
161
|
+
#
|
162
|
+
# map.resources :articles do |article|
|
163
|
+
# article.resources :comments
|
164
|
+
# end
|
165
|
+
#
|
166
|
+
# The comment resources work the same, but must now include a value for :article_id.
|
167
|
+
#
|
168
|
+
# comments_url(@article)
|
169
|
+
# comment_url(@article, @comment)
|
170
|
+
#
|
171
|
+
# comments_url(:article_id => @article)
|
172
|
+
# comment_url(:article_id => @article, :id => @comment)
|
173
|
+
#
|
174
|
+
# * <tt>:name_prefix</tt> -- define a prefix for all generated routes, usually ending in an underscore.
|
175
|
+
# Use this if you have named routes that may clash.
|
176
|
+
#
|
177
|
+
# map.resources :tags, :path_prefix => '/books/:book_id', :name_prefix => 'book_'
|
178
|
+
# map.resources :tags, :path_prefix => '/toys/:toy_id', :name_prefix => 'toy_'
|
179
|
+
#
|
180
|
+
# * <tt>:collection</tt> -- add named routes for other actions that operate on the collection.
|
181
|
+
# Takes a hash of <tt>#{action} => #{method}</tt>, where method is <tt>:get</tt>/<tt>:post</tt>/<tt>:put</tt>/<tt>:delete</tt>
|
182
|
+
# or <tt>:any</tt> if the method does not matter. These routes map to a URL like /messages;rss, with a route of rss_messages_url.
|
183
|
+
# * <tt>:member</tt> -- same as :collection, but for actions that operate on a specific member.
|
184
|
+
# * <tt>:new</tt> -- same as :collection, but for actions that operate on the new resource action.
|
185
|
+
#
|
186
|
+
# If <tt>map.resources</tt> is called with multiple resources, they all get the same options applied.
|
187
|
+
#
|
188
|
+
# Examples:
|
189
|
+
#
|
190
|
+
# map.resources :messages, :path_prefix => "/thread/:thread_id"
|
191
|
+
# # --> GET /thread/7/messages/1
|
192
|
+
#
|
193
|
+
# map.resources :messages, :collection => { :rss => :get }
|
194
|
+
# # --> GET /messages;rss (maps to the #rss action)
|
195
|
+
# # also adds a named route called "rss_messages"
|
196
|
+
#
|
197
|
+
# map.resources :messages, :member => { :mark => :post }
|
198
|
+
# # --> POST /messages/1;mark (maps to the #mark action)
|
199
|
+
# # also adds a named route called "mark_message"
|
200
|
+
#
|
201
|
+
# map.resources :messages, :new => { :preview => :post }
|
202
|
+
# # --> POST /messages/new;preview (maps to the #preview action)
|
203
|
+
# # also adds a named route called "preview_new_message"
|
204
|
+
#
|
205
|
+
# map.resources :messages, :new => { :new => :any, :preview => :post }
|
206
|
+
# # --> POST /messages/new;preview (maps to the #preview action)
|
207
|
+
# # also adds a named route called "preview_new_message"
|
208
|
+
# # --> /messages/new can be invoked via any request method
|
209
|
+
#
|
210
|
+
# map.resources :messages, :controller => "categories",
|
211
|
+
# :path_prefix => "/category/:category_id",
|
212
|
+
# :name_prefix => "category_"
|
213
|
+
# # --> GET /categories/7/messages/1
|
214
|
+
# # has named route "category_message"
|
215
|
+
def resources(*entities, &block)
|
216
|
+
options = entities.last.is_a?(Hash) ? entities.pop : { }
|
217
|
+
entities.each { |entity| map_resource entity, options.dup, &block }
|
218
|
+
end
|
219
|
+
|
220
|
+
private
|
221
|
+
def map_resource(entities, options = {}, &block)
|
222
|
+
resource = Resource.new(entities, options)
|
223
|
+
|
224
|
+
with_options :controller => resource.controller do |map|
|
225
|
+
map_collection_actions(map, resource)
|
226
|
+
map_new_actions(map, resource)
|
227
|
+
map_member_actions(map, resource)
|
228
|
+
|
229
|
+
if block_given?
|
230
|
+
with_options(:path_prefix => resource.nesting_path_prefix, &block)
|
231
|
+
end
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
235
|
+
def map_collection_actions(map, resource)
|
236
|
+
resource.collection_methods.each do |method, actions|
|
237
|
+
route_options = requirements_for(method)
|
238
|
+
|
239
|
+
actions.each do |action|
|
240
|
+
map.named_route(
|
241
|
+
"#{resource.name_prefix}#{action}_#{resource.plural}",
|
242
|
+
"#{resource.path};#{action}",
|
243
|
+
route_options.merge(:action => action.to_s)
|
244
|
+
)
|
245
|
+
|
246
|
+
map.named_route(
|
247
|
+
"formatted_#{resource.name_prefix}#{action}_#{resource.plural}",
|
248
|
+
"#{resource.path}.:format;#{action}",
|
249
|
+
route_options.merge(:action => action.to_s)
|
250
|
+
)
|
251
|
+
end
|
252
|
+
end
|
253
|
+
|
254
|
+
map.named_route("#{resource.name_prefix}#{resource.plural}", resource.path, :action => "index", :conditions => { :method => :get })
|
255
|
+
map.named_route("formatted_#{resource.name_prefix}#{resource.plural}", "#{resource.path}.:format", :action => "index", :conditions => { :method => :get })
|
256
|
+
|
257
|
+
map.connect(resource.path, :action => "create", :conditions => { :method => :post })
|
258
|
+
map.connect("#{resource.path}.:format", :action => "create", :conditions => { :method => :post })
|
259
|
+
end
|
260
|
+
|
261
|
+
def map_new_actions(map, resource)
|
262
|
+
resource.new_methods.each do |method, actions|
|
263
|
+
route_options = requirements_for(method)
|
264
|
+
actions.each do |action|
|
265
|
+
if action == :new
|
266
|
+
map.named_route("#{resource.name_prefix}new_#{resource.singular}", resource.new_path, route_options.merge(:action => "new"))
|
267
|
+
map.named_route("formatted_#{resource.name_prefix}new_#{resource.singular}", "#{resource.new_path}.:format", route_options.merge(:action => "new"))
|
268
|
+
else
|
269
|
+
map.named_route("#{resource.name_prefix}#{action}_new_#{resource.singular}", "#{resource.new_path};#{action}", route_options.merge(:action => action.to_s))
|
270
|
+
map.named_route("formatted_#{resource.name_prefix}#{action}_new_#{resource.singular}", "#{resource.new_path}.:format;#{action}", route_options.merge(:action => action.to_s))
|
271
|
+
end
|
272
|
+
end
|
273
|
+
end
|
274
|
+
end
|
275
|
+
|
276
|
+
def map_member_actions(map, resource)
|
277
|
+
resource.member_methods.each do |method, actions|
|
278
|
+
route_options = requirements_for(method)
|
279
|
+
|
280
|
+
actions.each do |action|
|
281
|
+
map.named_route("#{resource.name_prefix}#{action}_#{resource.singular}", "#{resource.member_path};#{action}", route_options.merge(:action => action.to_s))
|
282
|
+
map.named_route("formatted_#{resource.name_prefix}#{action}_#{resource.singular}", "#{resource.member_path}.:format;#{action}", route_options.merge(:action => action.to_s))
|
283
|
+
end
|
284
|
+
end
|
285
|
+
|
286
|
+
map.named_route("#{resource.name_prefix}#{resource.singular}", resource.member_path, :action => "show", :conditions => { :method => :get })
|
287
|
+
map.named_route("formatted_#{resource.name_prefix}#{resource.singular}", "#{resource.member_path}.:format", :action => "show", :conditions => { :method => :get })
|
288
|
+
|
289
|
+
map.connect(resource.member_path, :action => "update", :conditions => { :method => :put })
|
290
|
+
map.connect("#{resource.member_path}.:format", :action => "update", :conditions => { :method => :put })
|
291
|
+
|
292
|
+
map.connect(resource.member_path, :action => "destroy", :conditions => { :method => :delete })
|
293
|
+
map.connect("#{resource.member_path}.:format", :action => "destroy", :conditions => { :method => :delete })
|
294
|
+
end
|
295
|
+
|
296
|
+
def requirements_for(method)
|
297
|
+
method == :any ? {} : { :conditions => { :method => method } }
|
298
|
+
end
|
299
|
+
end
|
300
|
+
end
|
301
|
+
|
302
|
+
ActionController::Routing::RouteSet::Mapper.send :include, ActionController::Resources
|