actionpack 1.4.0 → 1.5.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 +66 -0
- data/README +94 -64
- data/install.rb +1 -20
- data/lib/action_controller.rb +15 -7
- data/lib/action_controller/assertions/action_pack_assertions.rb +56 -3
- data/lib/action_controller/base.rb +137 -64
- data/lib/action_controller/caching.rb +11 -11
- data/lib/action_controller/cgi_ext/cgi_ext.rb +2 -2
- data/lib/action_controller/cgi_ext/raw_post_data_fix.rb +4 -4
- data/lib/action_controller/cgi_process.rb +9 -1
- data/lib/action_controller/components.rb +73 -0
- data/lib/action_controller/cookies.rb +1 -1
- data/lib/action_controller/dependencies.rb +6 -1
- data/lib/action_controller/filters.rb +1 -1
- data/lib/action_controller/flash.rb +3 -3
- data/lib/action_controller/helpers.rb +17 -21
- data/lib/action_controller/layout.rb +2 -2
- data/lib/action_controller/request.rb +16 -6
- data/lib/action_controller/rescue.rb +15 -3
- data/lib/action_controller/routing.rb +304 -0
- data/lib/action_controller/scaffolding.rb +10 -12
- data/lib/action_controller/session/active_record_store.rb +4 -7
- data/lib/action_controller/session/mem_cache_store.rb +2 -2
- data/lib/action_controller/templates/rescues/_request_and_response.rhtml +9 -1
- data/lib/action_controller/templates/rescues/diagnostics.rhtml +1 -1
- data/lib/action_controller/templates/rescues/routing_error.rhtml +8 -0
- data/lib/action_controller/test_process.rb +29 -7
- data/lib/action_controller/url_rewriter.rb +28 -112
- data/lib/action_view.rb +1 -1
- data/lib/action_view/base.rb +44 -17
- data/lib/action_view/helpers/active_record_helper.rb +1 -1
- data/lib/action_view/helpers/asset_tag_helper.rb +59 -0
- data/lib/action_view/helpers/date_helper.rb +24 -13
- data/lib/action_view/helpers/form_helper.rb +6 -1
- data/lib/action_view/helpers/form_options_helper.rb +87 -9
- data/lib/action_view/helpers/form_tag_helper.rb +80 -0
- data/lib/action_view/helpers/tag_helper.rb +0 -23
- data/lib/action_view/helpers/text_helper.rb +26 -1
- data/lib/action_view/helpers/url_helper.rb +29 -35
- data/lib/action_view/partials.rb +2 -2
- data/lib/action_view/vendor/builder/xmlbase.rb +3 -3
- data/rakefile +5 -2
- data/test/abstract_unit.rb +3 -1
- data/test/controller/action_pack_assertions_test.rb +29 -1
- data/test/controller/active_record_assertions_test.rb +109 -101
- data/test/controller/base_tests.rb +72 -0
- data/test/controller/components_test.rb +74 -0
- data/test/controller/cookie_test.rb +0 -9
- data/test/controller/custom_handler_test.rb +33 -0
- data/test/controller/filters_test.rb +36 -0
- data/test/controller/helper_test.rb +27 -10
- data/test/controller/redirect_test.rb +23 -31
- data/test/controller/render_test.rb +81 -66
- data/test/controller/request_test.rb +22 -0
- data/test/controller/routing_tests.rb +490 -0
- data/test/controller/{url_test.rb → url_obsolete.rb} +24 -14
- data/test/controller/url_obsolete.rb.rej +747 -0
- data/test/fixtures/fun/games/hello_world.rhtml +1 -0
- data/test/fixtures/helpers/fun/games_helper.rb +3 -0
- data/test/template/asset_tag_helper_test.rb +45 -0
- data/test/template/form_options_helper_test.rb +161 -1
- data/test/template/form_tag_helper_test.rb +22 -0
- data/test/template/text_helper_test.rb +7 -0
- data/test/template/url_helper_test.rb +5 -2
- data/test/template/url_helper_test.rb.rej +105 -0
- metadata +32 -27
- data/lib/action_controller/support/binding_of_caller.rb +0 -83
- data/lib/action_controller/support/breakpoint.rb +0 -518
- data/lib/action_controller/support/class_attribute_accessors.rb +0 -57
- data/lib/action_controller/support/class_inheritable_attributes.rb +0 -117
- data/lib/action_controller/support/clean_logger.rb +0 -10
- data/lib/action_controller/support/core_ext.rb +0 -1
- data/lib/action_controller/support/core_ext/hash.rb +0 -5
- data/lib/action_controller/support/core_ext/hash/keys.rb +0 -35
- data/lib/action_controller/support/core_ext/numeric.rb +0 -7
- data/lib/action_controller/support/core_ext/numeric/bytes.rb +0 -33
- data/lib/action_controller/support/core_ext/numeric/time.rb +0 -59
- data/lib/action_controller/support/core_ext/object_and_class.rb +0 -24
- data/lib/action_controller/support/core_ext/string.rb +0 -5
- data/lib/action_controller/support/core_ext/string/inflections.rb +0 -45
- data/lib/action_controller/support/dependencies.rb +0 -63
- data/lib/action_controller/support/inflector.rb +0 -84
- data/lib/action_controller/support/misc.rb +0 -8
- data/lib/action_controller/support/module_attribute_accessors.rb +0 -57
@@ -1,9 +1,10 @@
|
|
1
1
|
require 'action_controller/request'
|
2
2
|
require 'action_controller/response'
|
3
|
+
require 'action_controller/routing'
|
3
4
|
require 'action_controller/url_rewriter'
|
4
|
-
require '
|
5
|
-
require '
|
6
|
-
require '
|
5
|
+
require 'active_support/class_attribute_accessors'
|
6
|
+
require 'active_support/class_inheritable_attributes'
|
7
|
+
require 'active_support/inflector'
|
7
8
|
require 'drb'
|
8
9
|
|
9
10
|
module ActionController #:nodoc:
|
@@ -13,6 +14,15 @@ module ActionController #:nodoc:
|
|
13
14
|
end
|
14
15
|
class MissingTemplate < ActionControllerError #:nodoc:
|
15
16
|
end
|
17
|
+
class RoutingError < ActionControllerError#:nodoc:
|
18
|
+
attr_reader :failures
|
19
|
+
def initialize(message, failures=[])
|
20
|
+
super(message)
|
21
|
+
@failures = failures
|
22
|
+
end
|
23
|
+
end
|
24
|
+
class UnknownController < ActionControllerError #:nodoc:
|
25
|
+
end
|
16
26
|
class UnknownAction < ActionControllerError #:nodoc:
|
17
27
|
end
|
18
28
|
class MissingFile < ActionControllerError #:nodoc:
|
@@ -76,9 +86,9 @@ module ActionController #:nodoc:
|
|
76
86
|
# <input type="text" name="post[name]" value="david">
|
77
87
|
# <input type="text" name="post[address]" value="hyacintvej">
|
78
88
|
#
|
79
|
-
# A request stemming from a form holding these inputs will include { "post"
|
89
|
+
# A request stemming from a form holding these inputs will include <tt>{ "post" => { "name" => "david", "address" => "hyacintvej" } }</tt>.
|
80
90
|
# If the address input had been named "post[address][street]", the @params would have included
|
81
|
-
# { "post" => { "address" => { "street" => "hyacintvej" } } }
|
91
|
+
# <tt>{ "post" => { "address" => { "street" => "hyacintvej" } } }</tt>. There's no limit to the depth of the nesting.
|
82
92
|
#
|
83
93
|
# == Sessions
|
84
94
|
#
|
@@ -146,22 +156,20 @@ module ActionController #:nodoc:
|
|
146
156
|
#
|
147
157
|
# Redirects work by rewriting the URL of the current action. So if the show action was called by "/library/books/ISBN/0743536703/show",
|
148
158
|
# we can redirect to an edit action simply by doing <tt>redirect_to(:action => "edit")</tt>, which could throw the user to
|
149
|
-
# "/library/books/ISBN/0743536703/edit". Naturally, you'll need to setup the
|
150
|
-
#
|
159
|
+
# "/library/books/ISBN/0743536703/edit". Naturally, you'll need to setup the routes configuration file to point to the proper controller
|
160
|
+
# and action in the first place, but once you have, it can be rewritten with ease.
|
151
161
|
#
|
152
|
-
# Let's consider a bunch of examples on how to go from "/
|
153
|
-
#
|
154
|
-
# redirect_to(:action => "show", :action_prefix => "XTC/123") =>
|
155
|
-
# "http://www.singlefile.com/library/books/XTC/123/show"
|
162
|
+
# Let's consider a bunch of examples on how to go from "/clients/37signals/basecamp/project/dash" to somewhere else:
|
156
163
|
#
|
157
|
-
# redirect_to(:
|
158
|
-
#
|
164
|
+
# redirect_to(:action => "edit") =>
|
165
|
+
# /clients/37signals/basecamp/project/dash
|
166
|
+
#
|
167
|
+
# redirect_to(:client_name => "nextangle", :project_name => "rails") =>
|
168
|
+
# /clients/nextangle/rails/project/dash
|
159
169
|
#
|
160
|
-
#
|
161
|
-
# "http://www.singlefile.com/library/settings/"
|
170
|
+
# Those redirects happen under the configuration of:
|
162
171
|
#
|
163
|
-
#
|
164
|
-
# you an excellent understanding of the different options and what they do.
|
172
|
+
# map.connect 'clients/:client_name/:project_name/:controller/:action'
|
165
173
|
#
|
166
174
|
# == Calling multiple redirects or renders
|
167
175
|
#
|
@@ -205,10 +213,16 @@ module ActionController #:nodoc:
|
|
205
213
|
# should instead be implemented in the controller to determine when debugging screens should be shown.
|
206
214
|
@@consider_all_requests_local = true
|
207
215
|
cattr_accessor :consider_all_requests_local
|
216
|
+
|
217
|
+
# Enable or disable the collection of failure information for RoutingErrors.
|
218
|
+
# This information can be extremely useful when tweaking custom routes, but is
|
219
|
+
# pointless once routes have been tested and verified.
|
220
|
+
@@debug_routes = true
|
221
|
+
cattr_accessor :debug_routes
|
208
222
|
|
209
223
|
# Template root determines the base from which template references will be made. So a call to render("test/template")
|
210
224
|
# will be converted to "#{template_root}/test/template.rhtml".
|
211
|
-
|
225
|
+
class_inheritable_accessor :template_root
|
212
226
|
|
213
227
|
# The logger is used for generating information on the action run-time (including benchmarking) if available.
|
214
228
|
# Can be set to nil for no logging. Compatible with both Ruby's own Logger and Log4r loggers.
|
@@ -261,6 +275,41 @@ module ActionController #:nodoc:
|
|
261
275
|
def controller_name
|
262
276
|
Inflector.underscore(controller_class_name.sub(/Controller/, ""))
|
263
277
|
end
|
278
|
+
|
279
|
+
# Convert the class name from something like "OneModule::TwoModule::NeatController" to "one_module/two_module/neat".
|
280
|
+
def controller_path
|
281
|
+
components = self.name.to_s.split('::').collect { |name| name.underscore }
|
282
|
+
components[-1] = $1 if /^(.*)_controller$/ =~ components[-1]
|
283
|
+
components.shift if components.first == 'controllers' # Transitional conditional to accomodate root Controllers module
|
284
|
+
components.join('/')
|
285
|
+
end
|
286
|
+
|
287
|
+
# Return an array containing the names of public methods that have been marked hidden from the action processor.
|
288
|
+
# By default, all methods defined in ActionController::Base and included modules are hidden.
|
289
|
+
# More methods can be hidden using +hide_actions+.
|
290
|
+
def hidden_actions
|
291
|
+
write_inheritable_attribute(:hidden_actions, ActionController::Base.public_instance_methods) unless read_inheritable_attribute(:hidden_actions)
|
292
|
+
read_inheritable_attribute(:hidden_actions)
|
293
|
+
end
|
294
|
+
|
295
|
+
# Hide each of the given methods from being callable as actions.
|
296
|
+
def hide_action(*names)
|
297
|
+
write_inheritable_attribute(:hidden_actions, hidden_actions | names.collect {|n| n.to_s})
|
298
|
+
end
|
299
|
+
|
300
|
+
# Set the template root to be one directory behind the root dir of the controller. Examples:
|
301
|
+
# /code/weblog/components/admin/users_controller.rb with Admin::UsersController
|
302
|
+
# will use /code/weblog/components as template root
|
303
|
+
# and find templates in /code/weblog/components/admin/users/
|
304
|
+
#
|
305
|
+
# /code/weblog/components/admin/parties/users_controller.rb with Admin::Parties::UsersController
|
306
|
+
# will also use /code/weblog/components as template root
|
307
|
+
# and find templates in /code/weblog/components/admin/parties/users/
|
308
|
+
def uses_component_template_root
|
309
|
+
path_of_calling_controller = File.dirname(caller[0].split(/:\d+:/).first)
|
310
|
+
path_of_controller_root = path_of_calling_controller.sub(/#{controller_path.split("/")[0..-2]}$/, "")
|
311
|
+
self.template_root = path_of_controller_root
|
312
|
+
end
|
264
313
|
end
|
265
314
|
|
266
315
|
public
|
@@ -277,45 +326,65 @@ module ActionController #:nodoc:
|
|
277
326
|
return @response
|
278
327
|
end
|
279
328
|
|
280
|
-
# Returns
|
281
|
-
#
|
282
|
-
#
|
329
|
+
# Returns a URL that has been rewritten according to the options hash and the defined Routes.
|
330
|
+
# (For doing a complete redirect, use redirect_to).
|
331
|
+
# �
|
332
|
+
# <tt>url_for</tt> is used to:
|
333
|
+
# �
|
334
|
+
# All keys given to url_for are forwarded to the Route module save for the following:
|
335
|
+
# * <tt>:anchor</tt> -- specifies the anchor name to be appended to the path. For example,
|
336
|
+
# <tt>url_for :controller => 'posts', :action => 'show', :id => 10, :anchor => 'comments'</tt>
|
337
|
+
# will produce "/posts/show/10#comments".
|
338
|
+
# * <tt>:only_path</tt> -- if true, returns the absolute URL (omitting the protocol, host name, and port)
|
339
|
+
# * <tt>:host</tt> -- overrides the default (current) host if provided
|
340
|
+
# * <tt>:protocol</tt> -- overrides the default (current) protocol if provided
|
341
|
+
#
|
342
|
+
# The URL is generated from the remaining keys in the hash. A URL contains two key parts: the <base> and a query string.
|
343
|
+
# Routes composes a query string as the key/value pairs not included in the <base>.
|
344
|
+
#
|
345
|
+
# The default Routes setup supports a typical Rails path of "controller/action/id" where action and id are optional, with
|
346
|
+
# action defaulting to 'index' when not given. Here are some typical url_for statements and their corresponding URLs:
|
347
|
+
# �
|
348
|
+
# url_for :controller => 'posts', :action => 'recent' # => 'proto://host.com/posts/recent'
|
349
|
+
# url_for :controller => 'posts', :action => 'index' # => 'proto://host.com/posts'
|
350
|
+
# url_for :controller => 'posts', :action => 'show', :id => 10 # => 'proto://host.com/posts/show/10'
|
351
|
+
#
|
352
|
+
# When generating a new URL, missing values may be filled in from the current request's parameters. For example,
|
353
|
+
# <tt>url_for :action => 'some_action'</tt> will retain the current controller, as expected. This behavior extends to
|
354
|
+
# other parameters, including <tt>:controller</tt>, <tt>:id</tt>, and any other parameters that are placed into a Route's
|
355
|
+
# path.
|
356
|
+
# �
|
357
|
+
# The URL helpers such as <tt>url_for</tt> have a limited form of memory: when generating a new URL, they can look for
|
358
|
+
# missing values in the current request's parameters. Routes attempts to guess when a value should and should not be
|
359
|
+
# taken from the defaults. There are a few simple rules on how this is performed:
|
283
360
|
#
|
284
|
-
#
|
285
|
-
#
|
286
|
-
# '------> '--------------> action_prefix
|
287
|
-
# controller_prefix (or module)
|
361
|
+
# * If the controller name begins with a slash, no defaults are used: <tt>url_for :controller => '/home'</tt>
|
362
|
+
# * If the controller changes, the action will default to index unless provided
|
288
363
|
#
|
289
|
-
#
|
290
|
-
#
|
291
|
-
# * <tt>:module</tt> - serves as a alias to :controller_prefix (overwrites :controller_prefix unless its nil)
|
292
|
-
# * <tt>:controller</tt> - specifies a new controller and clears out everything after the controller name (including the action,
|
293
|
-
# the pre- and suffix, and all params), so called with "settings" gives "/library/settings/".
|
294
|
-
# * <tt>:action_prefix</tt> - specifies the string between the controller name and the action name, which would
|
295
|
-
# be "/ISBN/0743536703" for the example. Called with "/XTC/123/" gives "/library/books/XTC/123/show".
|
296
|
-
# * <tt>:action</tt> - specifies a new action, so called with "edit" gives "/library/books/ISBN/0743536703/edit"
|
297
|
-
# * <tt>:action_suffix</tt> - specifies the string after the action name, which would be empty for the example.
|
298
|
-
# Called with "/detailed" gives "/library/books/ISBN/0743536703/detailed".
|
299
|
-
# * <tt>:path_params</tt> - specifies a hash that contains keys mapping to the request parameter names. In the example,
|
300
|
-
# { "type" => "ISBN", "id" => "0743536703" } would be the path_params. It serves as another way of replacing part of
|
301
|
-
# the action_prefix or action_suffix. So passing { "type" => "XTC" } would give "/library/books/XTC/0743536703/show".
|
302
|
-
# * <tt>:id</tt> - shortcut where ":id => 5" can be used instead of specifying :path_params => { "id" => 5 }.
|
303
|
-
# Called with "123" gives "/library/books/ISBN/123/show".
|
304
|
-
# * <tt>:params</tt> - specifies a hash that represents the regular request parameters, such as { "cat" => 1,
|
305
|
-
# "origin" => "there"} that would give "?cat=1&origin=there". Called with { "temporary" => 1 } in the example would give
|
306
|
-
# "/library/books/ISBN/0743536703/show?temporary=1"
|
307
|
-
# * <tt>:anchor</tt> - specifies the anchor name to be appended to the path. Called with "x14" would give
|
308
|
-
# "/library/books/ISBN/0743536703/show#x14"
|
309
|
-
# * <tt>:only_path</tt> - if true, returns the absolute URL (omitting the protocol, host name, and port).
|
364
|
+
# The final rule is applied while the URL is being generated and is best illustrated by an example. Let us consider the
|
365
|
+
# route given by <tt>map.connect 'people/:last/:first/:action', :action => 'bio', :controller => 'people'</tt>.
|
310
366
|
#
|
311
|
-
#
|
367
|
+
# Suppose that the current URL is "people/hh/david/contacts". Let's consider a few different cases URLs which are generated
|
368
|
+
# from this page.
|
312
369
|
#
|
313
|
-
#
|
314
|
-
#
|
315
|
-
#
|
316
|
-
#
|
317
|
-
# redirect_to(:action => "publish", :action_prefix => "/published", :anchor => "x14")
|
370
|
+
# * <tt>url_for :action => 'bio'</tt> -- During the generation of this URL, default values will be used for the first and
|
371
|
+
# last components, and the action shall change. The generated URL will be, "people/david/hh/bio".
|
372
|
+
# * <tt>url_for :first => 'davids-little-brother'</tt> This generates the URL 'people/hh/davids-little-brother' -- note
|
373
|
+
# that this URL leaves out the assumed action of 'bio'.
|
318
374
|
#
|
375
|
+
# However, you might ask why the action from the current request, 'contacts', isn't carried over into the new URL. The
|
376
|
+
# answer has to do with the order in which the parameters appear in the generated path. In a nutshell, since the
|
377
|
+
# value that appears in the slot for <tt>:first</tt> is not equal to default value for <tt>:first</tt> we stop using
|
378
|
+
# defaults. On it's own, this rule can account for much of the typical Rails URL behavior.
|
379
|
+
# �
|
380
|
+
# Although a convienence, defaults can occasionaly get in your way. In some cases a default persists longer than desired.
|
381
|
+
# The default may be cleared by adding <tt>:name => nil</tt> to <tt>url_for</tt>'s options.
|
382
|
+
# This is often required when writing form helpers, since the defaults in play may vary greatly depending upon where the
|
383
|
+
# helper is used from. The following line will redirect to PostController's default action, regardless of the page it is
|
384
|
+
# displayed on:
|
385
|
+
#
|
386
|
+
# url_for :controller => 'posts', :action => nil
|
387
|
+
#
|
319
388
|
# Instead of passing an options hash, you can also pass a method reference in the form of a symbol. Consider this example:
|
320
389
|
#
|
321
390
|
# class WeblogController < ActionController::Base
|
@@ -337,10 +406,6 @@ module ActionController #:nodoc:
|
|
337
406
|
end
|
338
407
|
end
|
339
408
|
|
340
|
-
def module_name
|
341
|
-
@params["module"]
|
342
|
-
end
|
343
|
-
|
344
409
|
# Converts the class name from something like "OneModule::TwoModule::NeatController" to "NeatController".
|
345
410
|
def controller_class_name
|
346
411
|
self.class.controller_class_name
|
@@ -405,10 +470,16 @@ module ActionController #:nodoc:
|
|
405
470
|
|
406
471
|
# Renders an empty response that can be used when the request is only interested in triggering an effect. Do note that good
|
407
472
|
# HTTP manners mandate that you don't use GET requests to trigger data changes.
|
408
|
-
def render_nothing(status = nil)
|
473
|
+
def render_nothing(status = nil) #:doc:
|
409
474
|
render_text "", status
|
410
475
|
end
|
411
476
|
|
477
|
+
# Returns the result of the render as a string.
|
478
|
+
def render_to_string(template_name = default_template_name) #:doc:
|
479
|
+
add_variables_to_assigns
|
480
|
+
@template.render_file(template_name)
|
481
|
+
end
|
482
|
+
|
412
483
|
# Sends the file by streaming it 4096 bytes at a time. This way the
|
413
484
|
# whole file doesn't need to be read into memory at once. This makes
|
414
485
|
# it feasible to send even large files.
|
@@ -458,6 +529,8 @@ module ActionController #:nodoc:
|
|
458
529
|
options[:filename] ||= File.basename(path)
|
459
530
|
send_file_headers! options
|
460
531
|
|
532
|
+
@performed_render = false
|
533
|
+
|
461
534
|
if options[:stream]
|
462
535
|
render_text do
|
463
536
|
logger.info "Streaming file #{path}" unless logger.nil?
|
@@ -506,6 +579,7 @@ module ActionController #:nodoc:
|
|
506
579
|
def send_data(data, options = {}) #:doc:
|
507
580
|
logger.info "Sending data #{options[:filename]}" unless logger.nil?
|
508
581
|
send_file_headers! options.merge(:length => data.size)
|
582
|
+
@performed_render = false
|
509
583
|
render_text data
|
510
584
|
end
|
511
585
|
|
@@ -521,7 +595,7 @@ module ActionController #:nodoc:
|
|
521
595
|
# the form of a hash, just like the one you would use for url_for directly. Example:
|
522
596
|
#
|
523
597
|
# def default_url_options(options)
|
524
|
-
# { :
|
598
|
+
# { :project => @project.active? ? @project.url_name : "unknown" }
|
525
599
|
# end
|
526
600
|
#
|
527
601
|
# As you can infer from the example, this is mostly useful for situations where you want to centralize dynamic decisions about the
|
@@ -558,7 +632,7 @@ module ActionController #:nodoc:
|
|
558
632
|
@performed_redirect = true
|
559
633
|
end
|
560
634
|
|
561
|
-
# Resets the session by
|
635
|
+
# Resets the session by clearing out all the objects stored within and initializing a new session object.
|
562
636
|
def reset_session #:doc:
|
563
637
|
@request.reset_session
|
564
638
|
@session = @request.session
|
@@ -594,7 +668,7 @@ module ActionController #:nodoc:
|
|
594
668
|
end
|
595
669
|
|
596
670
|
def initialize_current_url
|
597
|
-
@url = UrlRewriter.new(@request,
|
671
|
+
@url = UrlRewriter.new(@request, @params.clone())
|
598
672
|
end
|
599
673
|
|
600
674
|
def log_processing
|
@@ -618,10 +692,9 @@ module ActionController #:nodoc:
|
|
618
692
|
end
|
619
693
|
|
620
694
|
def action_methods
|
621
|
-
|
622
|
-
action_controller_classes.inject([]) { |action_methods, klass| action_methods + klass.public_instance_methods(false) }
|
695
|
+
@action_methods ||= (self.class.public_instance_methods - self.class.hidden_actions)
|
623
696
|
end
|
624
|
-
|
697
|
+
|
625
698
|
def add_variables_to_assigns
|
626
699
|
add_instance_variables_to_assigns
|
627
700
|
add_class_variables_to_assigns if view_controller_internals
|
@@ -691,7 +764,7 @@ module ActionController #:nodoc:
|
|
691
764
|
end
|
692
765
|
|
693
766
|
def default_template_name(default_action_name = action_name)
|
694
|
-
|
767
|
+
"#{self.class.controller_path}/#{default_action_name}"
|
695
768
|
end
|
696
769
|
end
|
697
770
|
end
|
@@ -23,7 +23,7 @@ module ActionController #:nodoc:
|
|
23
23
|
# are treated the same. Content management systems -- including weblogs and wikis -- have many pages that are a great fit
|
24
24
|
# for this approach, but account-based systems where people log in and manipulate their own data are often less likely candidates.
|
25
25
|
#
|
26
|
-
# Specifying which actions to
|
26
|
+
# Specifying which actions to cache is done through the <tt>caches</tt> class method:
|
27
27
|
#
|
28
28
|
# class WeblogController < ActionController::Base
|
29
29
|
# caches_page :show, :new
|
@@ -67,7 +67,7 @@ module ActionController #:nodoc:
|
|
67
67
|
def expire_page(path)
|
68
68
|
return unless perform_caching
|
69
69
|
File.delete(page_cache_path(path)) if File.exists?(page_cache_path(path))
|
70
|
-
logger.info "Expired page: #{path}" unless logger.nil?
|
70
|
+
logger.info "Expired page: #{page_cache_file(path)}" unless logger.nil?
|
71
71
|
end
|
72
72
|
|
73
73
|
# Manually cache the +content+ in the key determined by +path+. Example:
|
@@ -76,7 +76,7 @@ module ActionController #:nodoc:
|
|
76
76
|
return unless perform_caching
|
77
77
|
FileUtils.makedirs(File.dirname(page_cache_path(path)))
|
78
78
|
File.open(page_cache_path(path), "w+") { |f| f.write(content) }
|
79
|
-
logger.info "Cached page: #{path}" unless logger.nil?
|
79
|
+
logger.info "Cached page: #{page_cache_file(path)}" unless logger.nil?
|
80
80
|
end
|
81
81
|
|
82
82
|
# Caches the +actions+ using the page-caching approach that'll store the cache in a path within the page_cache_directory that
|
@@ -89,12 +89,12 @@ module ActionController #:nodoc:
|
|
89
89
|
end
|
90
90
|
|
91
91
|
private
|
92
|
+
def page_cache_file(path)
|
93
|
+
(path.empty? ? "/index" : path) + ".html"
|
94
|
+
end
|
95
|
+
|
92
96
|
def page_cache_path(path)
|
93
|
-
|
94
|
-
page_cache_directory + path + '/index'
|
95
|
-
else
|
96
|
-
page_cache_directory + path
|
97
|
-
end
|
97
|
+
page_cache_directory + page_cache_file(path)
|
98
98
|
end
|
99
99
|
end
|
100
100
|
|
@@ -121,7 +121,7 @@ module ActionController #:nodoc:
|
|
121
121
|
|
122
122
|
private
|
123
123
|
def caching_allowed
|
124
|
-
!@request.post?
|
124
|
+
!@request.post?
|
125
125
|
end
|
126
126
|
end
|
127
127
|
|
@@ -308,13 +308,13 @@ module ActionController #:nodoc:
|
|
308
308
|
|
309
309
|
class DRbStore < MemoryStore #:nodoc:
|
310
310
|
def initialize(address = 'druby://localhost:9192')
|
311
|
-
@data = DRbObject.new(nil, address)
|
311
|
+
@data, @mutex = DRbObject.new(nil, address), Mutex.new
|
312
312
|
end
|
313
313
|
end
|
314
314
|
|
315
315
|
class MemCacheStore < MemoryStore #:nodoc:
|
316
316
|
def initialize(address = 'localhost')
|
317
|
-
@data = MemCache.new(address)
|
317
|
+
@data, @mutex = MemCache.new(address), Mutex.new
|
318
318
|
end
|
319
319
|
end
|
320
320
|
|
@@ -4,7 +4,7 @@ require 'cgi/session/pstore'
|
|
4
4
|
require 'action_controller/cgi_ext/cgi_methods'
|
5
5
|
|
6
6
|
# Wrapper around the CGIMethods that have been secluded to allow testing without
|
7
|
-
# an
|
7
|
+
# an instantiated CGI object
|
8
8
|
class CGI #:nodoc:
|
9
9
|
class << self
|
10
10
|
alias :escapeHTML_fail_on_nil :escapeHTML
|
@@ -40,4 +40,4 @@ class CGI #:nodoc:
|
|
40
40
|
parameters['database_manager'] = CGI::Session::PStore
|
41
41
|
CGI::Session.new(self, parameters)
|
42
42
|
end
|
43
|
-
end
|
43
|
+
end
|
@@ -14,7 +14,7 @@ class CGI #:nodoc:
|
|
14
14
|
@params = CGI::parse(read_query_params)
|
15
15
|
end
|
16
16
|
|
17
|
-
@cookies = CGI::Cookie::parse((env_table['HTTP_COOKIE']
|
17
|
+
@cookies = CGI::Cookie::parse((env_table['HTTP_COOKIE'] || env_table['COOKIE']))
|
18
18
|
end
|
19
19
|
|
20
20
|
private
|
@@ -30,13 +30,13 @@ class CGI #:nodoc:
|
|
30
30
|
case env_table['REQUEST_METHOD']
|
31
31
|
when 'GET', 'HEAD'
|
32
32
|
if defined? MOD_RUBY
|
33
|
-
Apache::request.args
|
33
|
+
Apache::request.args || ''
|
34
34
|
else
|
35
|
-
env_table['QUERY_STRING']
|
35
|
+
env_table['QUERY_STRING'] || ''
|
36
36
|
end
|
37
37
|
when 'POST'
|
38
38
|
stdinput.binmode if stdinput.respond_to?(:binmode)
|
39
|
-
content = stdinput.read(Integer(env_table['CONTENT_LENGTH']))
|
39
|
+
content = stdinput.read(Integer(env_table['CONTENT_LENGTH'])) || ''
|
40
40
|
env_table['RAW_POST_DATA'] = content.freeze
|
41
41
|
else
|
42
42
|
read_from_cmdline
|
@@ -46,8 +46,16 @@ module ActionController #:nodoc:
|
|
46
46
|
super()
|
47
47
|
end
|
48
48
|
|
49
|
+
def query_string
|
50
|
+
return @cgi.query_string unless @cgi.query_string.nil? || @cgi.query_string.empty?
|
51
|
+
parts = env['REQUEST_URI'].split('?')
|
52
|
+
parts.shift
|
53
|
+
return parts.join('?')
|
54
|
+
end
|
55
|
+
|
49
56
|
def query_parameters
|
50
|
-
|
57
|
+
qs = self.query_string
|
58
|
+
qs.empty? ? {} : CGIMethods.parse_query_parameters(query_string)
|
51
59
|
end
|
52
60
|
|
53
61
|
def request_parameters
|
@@ -0,0 +1,73 @@
|
|
1
|
+
module ActionController #:nodoc:
|
2
|
+
# Components allows you to call other actions for their rendered response while execution another action. You can either delegate
|
3
|
+
# the entire response rendering or you can mix a partial response in with your other content.
|
4
|
+
#
|
5
|
+
# class WeblogController < ActionController::Base
|
6
|
+
# # Performs a method and then lets hello_world output its render
|
7
|
+
# def delegate_action
|
8
|
+
# do_other_stuff_before_hello_world
|
9
|
+
# render_component :controller => "greeter", :action => "hello_world"
|
10
|
+
# end
|
11
|
+
# end
|
12
|
+
#
|
13
|
+
# class GreeterController < ActionController::Base
|
14
|
+
# def hello_world
|
15
|
+
# render_text "Hello World!"
|
16
|
+
# end
|
17
|
+
# end
|
18
|
+
#
|
19
|
+
# The same can be done in a view to do a partial rendering:
|
20
|
+
#
|
21
|
+
# Let's see a greeting:
|
22
|
+
# <%= render_component :controller => "greeter", :action => "hello_world" %>
|
23
|
+
module Components
|
24
|
+
def self.append_features(base) #:nodoc:
|
25
|
+
super
|
26
|
+
base.helper do
|
27
|
+
def render_component(options)
|
28
|
+
@controller.send(:render_component_as_string, options)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
protected
|
34
|
+
# Renders the component specified as the response for the current method
|
35
|
+
def render_component(options = {}) #:doc:
|
36
|
+
component_logging(options) { render_text(component_response(options).body, response.headers["Status"]) }
|
37
|
+
end
|
38
|
+
|
39
|
+
# Returns the component response as a string
|
40
|
+
def render_component_as_string(options) #:doc:
|
41
|
+
component_logging(options) { component_response(options, false).body }
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
def component_response(options, reuse_response = true)
|
46
|
+
component_class(options).process(request_for_component(options), reuse_response ? @response : response_for_component)
|
47
|
+
end
|
48
|
+
|
49
|
+
def component_class(options)
|
50
|
+
options[:controller] ? (options[:controller].camelize + "Controller").constantize : self.class
|
51
|
+
end
|
52
|
+
|
53
|
+
def request_for_component(options)
|
54
|
+
request_for_component = @request.dup
|
55
|
+
request_for_component.send(
|
56
|
+
:instance_variable_set, :@parameters,
|
57
|
+
(options[:params] || {}).merge({ "controller" => options[:controller], "action" => options[:action] })
|
58
|
+
)
|
59
|
+
return request_for_component
|
60
|
+
end
|
61
|
+
|
62
|
+
def response_for_component
|
63
|
+
@response.dup
|
64
|
+
end
|
65
|
+
|
66
|
+
def component_logging(options)
|
67
|
+
logger.info("Start rendering component (#{options.inspect}): ") unless logger.nil?
|
68
|
+
result = yield
|
69
|
+
logger.info("\n\nEnd of component rendering") unless logger.nil?
|
70
|
+
return result
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|