actionpack 1.6.0 → 1.7.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 +39 -0
- data/lib/action_controller.rb +2 -0
- data/lib/action_controller/base.rb +9 -0
- data/lib/action_controller/caching.rb +42 -3
- data/lib/action_controller/cgi_ext/raw_post_data_fix.rb +1 -1
- data/lib/action_controller/dependencies.rb +3 -9
- data/lib/action_controller/helpers.rb +6 -6
- data/lib/action_controller/rescue.rb +2 -2
- data/lib/action_controller/routing.rb +1 -1
- data/lib/action_controller/templates/rescues/_request_and_response.rhtml +15 -12
- data/lib/action_controller/test_process.rb +2 -1
- data/lib/action_controller/url_rewriter.rb +13 -47
- data/lib/action_controller/verification.rb +79 -0
- data/lib/action_view/helpers/date_helper.rb +18 -7
- data/lib/action_view/helpers/javascript_helper.rb +8 -6
- data/lib/action_view/helpers/javascripts/prototype.js +133 -15
- data/lib/action_view/helpers/pagination_helper.rb +3 -3
- data/lib/action_view/helpers/text_helper.rb +20 -0
- data/rakefile +122 -23
- data/test/controller/helper_test.rb +1 -1
- data/test/controller/test_test.rb +25 -0
- data/test/controller/verification_test.rb +137 -0
- data/test/template/date_helper_test.rb +16 -0
- data/test/template/javascript_helper.rb +9 -0
- data/test/template/text_helper_test.rb +18 -0
- metadata +7 -4
- data/test/controller/url_obsolete.rb +0 -487
data/CHANGELOG
CHANGED
@@ -1,3 +1,42 @@
|
|
1
|
+
*1.7.0* (27th March, 2005)
|
2
|
+
|
3
|
+
* Added ActionController::Base.page_cache_extension for setting the page cache file extension (the default is .html) #903 [Andreas]
|
4
|
+
|
5
|
+
* Fixed "bad environment variable value" exception caused by Safari, Apache, and Ajax calls #918
|
6
|
+
|
7
|
+
* Fixed that pagination_helper would ignore :params #947 [Sebastian Kanthak]
|
8
|
+
|
9
|
+
* Added :owerwrite_params back to url_for and friends -- it was AWL since the introduction of Routes #921 [raphinou]
|
10
|
+
|
11
|
+
* Added :position option to link_to_remote/form_remote_tag that can be either :before, :top, :bottom, or :after and specifies where the return from the method should be inserted #952 [Matthew McCray/Sam Stephenson]
|
12
|
+
|
13
|
+
* Added Effect.Highlight to prototype.js to do Yellow Fade Technique (of 37signals' fame) on any container #952 [Sam Stephenson/courtenay]
|
14
|
+
|
15
|
+
* Added include_seconds option as the third parameter to distance_of_time_in_words which will render "less than a minute" in higher resolution ("less than 10 seconds" etc) #944 [thomas@fesch.at]
|
16
|
+
|
17
|
+
* Added fourth option to process in test cases to specify the content of the flash #949 [Jamis Buck]
|
18
|
+
|
19
|
+
* Added Verifications that allows you to specify preconditions to actions in form of statements like <tt>verify :only => :update_post, :params => "admin_privileges", :redirect_to => { :action => "settings" }</tt>, which ensure that the update_post action is only called if admin_privileges is available as a parameter -- otherwise the user is redirected to settings. #897 [Jamis Buck]
|
20
|
+
|
21
|
+
* Fixed Form.Serialize for the JavascriptHelper to also seriliaze password fields #934 [dweitzman@gmail.com]
|
22
|
+
|
23
|
+
* Added JavascriptHelper#escape_javascript as a public method (was private) and made it escape both single and double quotes and new lines #940 [mortonda@dgrmm.net]
|
24
|
+
|
25
|
+
* Added trailing_slash option to url_for, so you can generate urls ending in a slash. Note that is currently not recommended unless you need it for special reasons since it breaks caching #937 [stian@grytoyr.net]
|
26
|
+
|
27
|
+
* Added expire_matched_fragments(regular_expression) to clear out a lot of fragment caches at once #927 [technoweenie@gmail.com]
|
28
|
+
|
29
|
+
* Fixed the problems with : and ? in file names for fragment caches on Windows #927 [technoweenie@gmail.com]
|
30
|
+
|
31
|
+
* Added TextHelper#human_size for formatting file sizes, like human_size(1234567) => 1.2 MB #943 [thomas@fesch.at]
|
32
|
+
|
33
|
+
* Fixed link_to :confirm #936 [Nicholas Seckar]
|
34
|
+
|
35
|
+
* Improved error reporting especially around never shallowing exceptions. Debugging helpers should be much easier now #980 [Nicholas Seckar]
|
36
|
+
|
37
|
+
* Fixed Toggle.display in prototype.js #902 [Lucas Carlson]
|
38
|
+
|
39
|
+
|
1
40
|
*1.6.0* (22th March, 2005)
|
2
41
|
|
3
42
|
* Added a JavascriptHelper and accompanying prototype.js library that opens the world of Ajax to Action Pack with a large array of options for dynamically interacting with an application without reloading the page #884 [Sam Stephenson/David]
|
data/lib/action_controller.rb
CHANGED
@@ -46,6 +46,7 @@ require 'action_controller/cookies'
|
|
46
46
|
require 'action_controller/cgi_process'
|
47
47
|
require 'action_controller/caching'
|
48
48
|
require 'action_controller/components'
|
49
|
+
require 'action_controller/verification'
|
49
50
|
|
50
51
|
require 'action_view'
|
51
52
|
ActionController::Base.template_class = ActionView::Base
|
@@ -64,4 +65,5 @@ ActionController::Base.class_eval do
|
|
64
65
|
include ActionController::Session
|
65
66
|
include ActionController::Caching
|
66
67
|
include ActionController::Components
|
68
|
+
include ActionController::Verification
|
67
69
|
end
|
@@ -105,6 +105,13 @@ module ActionController #:nodoc:
|
|
105
105
|
# Any object can be placed in the session (as long as it can be Marshalled). But remember that 1000 active sessions each storing a
|
106
106
|
# 50kb object could lead to a 50MB memory overhead. In other words, think carefully about size and caching before resorting to the use
|
107
107
|
# of the session.
|
108
|
+
#
|
109
|
+
# If you store a model in the session, you must also include a line like:
|
110
|
+
#
|
111
|
+
# model :person
|
112
|
+
#
|
113
|
+
# For that particular controller. In Rails, you can also just add it in your app/controller/application.rb file (so the model is available
|
114
|
+
# for all controllers). This lets Action Pack know to have the model definition loaded before retrieving the object from the session.
|
108
115
|
#
|
109
116
|
# For removing objects from the session, you can either assign a single key to nil, like <tt>@session[:person] = nil</tt>, or you can
|
110
117
|
# remove the entire session with reset_session.
|
@@ -336,6 +343,8 @@ module ActionController #:nodoc:
|
|
336
343
|
# <tt>url_for :controller => 'posts', :action => 'show', :id => 10, :anchor => 'comments'</tt>
|
337
344
|
# will produce "/posts/show/10#comments".
|
338
345
|
# * <tt>:only_path</tt> -- if true, returns the absolute URL (omitting the protocol, host name, and port)
|
346
|
+
# * <tt>:trailing_slash</tt> -- if true, adds a trailing slash, as in "/archive/2005/". Note that this
|
347
|
+
# is currently not recommended since it breaks caching.
|
339
348
|
# * <tt>:host</tt> -- overrides the default (current) host if provided
|
340
349
|
# * <tt>:protocol</tt> -- overrides the default (current) protocol if provided
|
341
350
|
#
|
@@ -51,6 +51,11 @@ module ActionController #:nodoc:
|
|
51
51
|
#
|
52
52
|
# The cache directory should be the document root for the web server and is set using Base.page_cache_directory = "/document/root".
|
53
53
|
# For Rails, this directory has already been set to RAILS_ROOT + "/public".
|
54
|
+
#
|
55
|
+
# == Setting the cache extension
|
56
|
+
#
|
57
|
+
# By default, the cache extension is .html, which makes it easy for the cached files to be picked up by the web server. If you want
|
58
|
+
# something else, like .php or .shtml, just set Base.page_cache_extension.
|
54
59
|
module Pages
|
55
60
|
def self.append_features(base) #:nodoc:
|
56
61
|
super
|
@@ -58,6 +63,9 @@ module ActionController #:nodoc:
|
|
58
63
|
base.class_eval do
|
59
64
|
@@page_cache_directory = defined?(RAILS_ROOT) ? "#{RAILS_ROOT}/public" : ""
|
60
65
|
cattr_accessor :page_cache_directory
|
66
|
+
|
67
|
+
@@page_cache_extension = '.html'
|
68
|
+
cattr_accessor :page_cache_extension
|
61
69
|
end
|
62
70
|
end
|
63
71
|
|
@@ -91,7 +99,7 @@ module ActionController #:nodoc:
|
|
91
99
|
private
|
92
100
|
def page_cache_file(path)
|
93
101
|
name = ((path.empty? || path == "/") ? "/index" : path)
|
94
|
-
name <<
|
102
|
+
name << @@page_cache_extension unless (name.split('/').last || name).include? '.'
|
95
103
|
return name
|
96
104
|
end
|
97
105
|
|
@@ -285,7 +293,12 @@ module ActionController #:nodoc:
|
|
285
293
|
fragment_cache_store.delete(name, options)
|
286
294
|
logger.info "Expired fragment: #{name}" unless logger.nil?
|
287
295
|
end
|
288
|
-
|
296
|
+
|
297
|
+
def expire_matched_fragments(re=Regexp.new('/*/'), options = {})
|
298
|
+
fragment_cache_store.delete_matched(re, { :root_path => url_for.split('://').last.split('/').first })
|
299
|
+
logger.info "Expired all fragments matching: #{re} " unless logger.nil?
|
300
|
+
end
|
301
|
+
|
289
302
|
class MemoryStore #:nodoc:
|
290
303
|
def initialize
|
291
304
|
@data, @mutex = { }, Mutex.new
|
@@ -302,6 +315,10 @@ module ActionController #:nodoc:
|
|
302
315
|
def delete(name, options = {}) #:nodoc:
|
303
316
|
@mutex.synchronize { @data.delete(name) }
|
304
317
|
end
|
318
|
+
|
319
|
+
def delete_matched(re, options) #:nodoc:
|
320
|
+
@mutex.synchronize { @data.delete_if {|k,v| k.index(options[:root_path]) == 0 and k =~ re} }
|
321
|
+
end
|
305
322
|
end
|
306
323
|
|
307
324
|
class DRbStore < MemoryStore #:nodoc:
|
@@ -335,15 +352,37 @@ module ActionController #:nodoc:
|
|
335
352
|
def delete(name, options) #:nodoc:
|
336
353
|
File.delete(real_file_path(name)) if File.exist?(real_file_path(name))
|
337
354
|
end
|
355
|
+
|
356
|
+
def delete_matched(re, options) #:nodoc:
|
357
|
+
rootPath = real_file_path(options[:root_path])
|
358
|
+
search_dir(@cache_path).each do |f|
|
359
|
+
File.delete(f) if f.index(rootPath) == 0 and f =~ re and File.exist?(f)
|
360
|
+
end
|
361
|
+
end
|
338
362
|
|
339
363
|
private
|
340
364
|
def real_file_path(name)
|
341
|
-
|
365
|
+
'%s/%s' % [@cache_path, name.gsub('?', '.').gsub(':', '.')]
|
342
366
|
end
|
343
367
|
|
344
368
|
def ensure_cache_path(path)
|
345
369
|
FileUtils.makedirs(path) unless File.exists?(path)
|
346
370
|
end
|
371
|
+
|
372
|
+
def search_dir(dir)
|
373
|
+
require 'pathname'
|
374
|
+
files = []
|
375
|
+
dir = Dir.new(dir)
|
376
|
+
dir.each do |d|
|
377
|
+
unless d == '.' or d == '..'
|
378
|
+
d = File.join(dir.path, d)
|
379
|
+
p = Pathname.new(d)
|
380
|
+
files << p.to_s if p.file?
|
381
|
+
files += search_dir(d) if p.directory?
|
382
|
+
end
|
383
|
+
end
|
384
|
+
files
|
385
|
+
end
|
347
386
|
end
|
348
387
|
end
|
349
388
|
|
@@ -37,7 +37,7 @@ class CGI #:nodoc:
|
|
37
37
|
when 'POST'
|
38
38
|
stdinput.binmode if stdinput.respond_to?(:binmode)
|
39
39
|
content = stdinput.read(Integer(env_table['CONTENT_LENGTH'])) || ''
|
40
|
-
env_table['RAW_POST_DATA'] = content.freeze
|
40
|
+
env_table['RAW_POST_DATA'] = content.split("&_").first.freeze # &_ is a fix for Safari Ajax postings that always append \000
|
41
41
|
else
|
42
42
|
read_from_cmdline
|
43
43
|
end
|
@@ -71,8 +71,8 @@ module ActionController #:nodoc:
|
|
71
71
|
dependencies.flatten.each do |dependency|
|
72
72
|
begin
|
73
73
|
require_dependency(dependency.to_s)
|
74
|
-
rescue LoadError
|
75
|
-
raise LoadError
|
74
|
+
rescue LoadError => e
|
75
|
+
raise LoadError.new("Missing #{layer} #{dependency}.rb").copy_blame!(e)
|
76
76
|
rescue Object => exception
|
77
77
|
exception.blame_file! "=> #{layer} #{dependency}.rb"
|
78
78
|
raise
|
@@ -82,13 +82,7 @@ module ActionController #:nodoc:
|
|
82
82
|
|
83
83
|
def inherited(child)
|
84
84
|
inherited_without_model(child)
|
85
|
-
return if child.controller_name == "application" # otherwise the ApplicationController in Rails will include itself
|
86
|
-
begin
|
87
|
-
child.model(child.controller_name.singularize)
|
88
|
-
rescue NameError, LoadError
|
89
|
-
# No neither singular or plural model available for this controller
|
90
|
-
end
|
91
85
|
end
|
92
86
|
end
|
93
87
|
end
|
94
|
-
end
|
88
|
+
end
|
@@ -52,12 +52,13 @@ module ActionController #:nodoc:
|
|
52
52
|
when String, Symbol
|
53
53
|
file_name = arg.to_s.underscore + '_helper'
|
54
54
|
class_name = file_name.camelize
|
55
|
-
|
55
|
+
|
56
56
|
begin
|
57
57
|
require_dependency(file_name)
|
58
58
|
rescue LoadError => load_error
|
59
59
|
requiree = / -- (.*?)(\.rb)?$/.match(load_error).to_a[1]
|
60
|
-
|
60
|
+
msg = (requiree == file_name) ? "Missing helper file helpers/#{file_name}.rb" : "Can't load file: #{requiree}"
|
61
|
+
raise LoadError.new(msg).copy_blame!(load_error)
|
61
62
|
end
|
62
63
|
|
63
64
|
add_template_helper(class_name.constantize)
|
@@ -90,10 +91,9 @@ module ActionController #:nodoc:
|
|
90
91
|
private
|
91
92
|
def inherited(child)
|
92
93
|
inherited_without_helper(child)
|
93
|
-
begin
|
94
|
-
|
95
|
-
|
96
|
-
# No default helper available for this controller
|
94
|
+
begin child.helper(child.controller_path)
|
95
|
+
rescue MissingSourceFile => e
|
96
|
+
raise unless e.is_missing?("helpers/#{child.controller_path}_helper")
|
97
97
|
end
|
98
98
|
end
|
99
99
|
end
|
@@ -77,8 +77,8 @@ module ActionController #:nodoc:
|
|
77
77
|
def perform_action_with_rescue #:nodoc:
|
78
78
|
begin
|
79
79
|
perform_action_without_rescue
|
80
|
-
rescue => exception
|
81
|
-
if defined?(Breakpoint)
|
80
|
+
rescue Object => exception
|
81
|
+
if defined?(Breakpoint) && @params["BP-RETRY"]
|
82
82
|
msg = exception.backtrace.first
|
83
83
|
if md = /^(.+?):(\d+)(?::in `(.+)')?$/.match(msg) then
|
84
84
|
origin_file, origin_line = md[1], md[2].to_i
|
@@ -312,7 +312,7 @@ module ActionController
|
|
312
312
|
route_file = defined?(RAILS_ROOT) ? File.join(RAILS_ROOT, 'config', 'routes') : nil
|
313
313
|
require_dependency(route_file) if route_file
|
314
314
|
rescue LoadError, ScriptError => e
|
315
|
-
raise RoutingError
|
315
|
+
raise RoutingError.new("Cannot load config/routes.rb:\n #{e.message}").copy_blame!(e)
|
316
316
|
ensure # Ensure that there is at least one route:
|
317
317
|
connect(':controller/:action/:id', :action => 'index', :id => nil) if @routes.empty?
|
318
318
|
end
|
@@ -1,22 +1,25 @@
|
|
1
|
-
<%
|
2
|
-
|
3
|
-
|
1
|
+
<% unless @exception.blamed_files.blank? %>
|
2
|
+
<% if (hide = @exception.blamed_files.length > 8) %>
|
3
|
+
<a href="#" onclick="document.getElementById('blame_trace').style.display='block'; return false;">Show blamed files</a>
|
4
|
+
<% end %>
|
5
|
+
<pre id="blame_trace" <%='style="display:none"' if hide %>><code><%=h @exception.describe_blame %></code></pre>
|
4
6
|
<% end %>
|
5
7
|
|
6
8
|
<% if defined?(Breakpoint) %>
|
7
9
|
<br /><br />
|
8
|
-
<% begin
|
9
|
-
|
10
|
+
<% begin %>
|
11
|
+
<%= form_tag(@request.request_uri, "method" => @request.method) %>
|
12
|
+
<input type="hidden" name="BP-RETRY" value="1" />
|
10
13
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
14
|
+
<% for key, values in @params %>
|
15
|
+
<% next if key == "BP-RETRY" %>
|
16
|
+
<% for value in Array(values) %>
|
17
|
+
<input type="hidden" name="<%= key %>" value="<%= value %>" />
|
18
|
+
<% end %>
|
15
19
|
<% end %>
|
16
|
-
<% end %>
|
17
20
|
|
18
|
-
|
19
|
-
|
21
|
+
<input type="submit" value="Retry with Breakpoint" />
|
22
|
+
</form>
|
20
23
|
<% rescue Exception => e %>
|
21
24
|
<%=h "Couldn't render breakpoint link due to #{e.class} #{e.message}" %>
|
22
25
|
<% end %>
|
@@ -251,12 +251,13 @@ module Test
|
|
251
251
|
class TestCase #:nodoc:
|
252
252
|
private
|
253
253
|
# execute the request and set/volley the response
|
254
|
-
def process(action, parameters = nil, session = nil)
|
254
|
+
def process(action, parameters = nil, session = nil, flash = nil)
|
255
255
|
@request.env['REQUEST_METHOD'] ||= "GET"
|
256
256
|
@request.action = action.to_s
|
257
257
|
@request.path_parameters = { :controller => @controller.class.controller_path }
|
258
258
|
@request.parameters.update(parameters) unless parameters.nil?
|
259
259
|
@request.session = ActionController::TestSession.new(session) unless session.nil?
|
260
|
+
@request.session["flash"] = ActionController::Flash::FlashHash.new.update(flash) if flash
|
260
261
|
@controller.process(@request, @response)
|
261
262
|
end
|
262
263
|
|
@@ -2,10 +2,9 @@ module ActionController
|
|
2
2
|
# Rewrites URLs for Base.redirect_to and Base.url_for in the controller.
|
3
3
|
|
4
4
|
class UrlRewriter #:nodoc:
|
5
|
-
RESERVED_OPTIONS = [:anchor, :params, :only_path, :host, :protocol, :
|
5
|
+
RESERVED_OPTIONS = [:anchor, :params, :only_path, :host, :protocol, :trailing_slash]
|
6
6
|
def initialize(request, parameters)
|
7
7
|
@request, @parameters = request, parameters
|
8
|
-
@rewritten_path = @request.path ? @request.path.dup : ""
|
9
8
|
end
|
10
9
|
|
11
10
|
def rewrite(options = {})
|
@@ -19,14 +18,14 @@ module ActionController
|
|
19
18
|
alias_method :to_s, :to_str
|
20
19
|
|
21
20
|
private
|
22
|
-
def rewrite_url(path, options)
|
23
|
-
|
21
|
+
def rewrite_url(path, options)
|
24
22
|
rewritten_url = ""
|
25
23
|
rewritten_url << (options[:protocol] || @request.protocol) unless options[:only_path]
|
26
24
|
rewritten_url << (options[:host] || @request.host_with_port) unless options[:only_path]
|
27
25
|
|
28
|
-
rewritten_url <<
|
26
|
+
rewritten_url << @request.relative_url_root.to_s
|
29
27
|
rewritten_url << path
|
28
|
+
rewritten_url << '/' if options[:trailing_slash]
|
30
29
|
rewritten_url << "##{options[:anchor]}" if options[:anchor]
|
31
30
|
|
32
31
|
return rewritten_url
|
@@ -34,10 +33,17 @@ module ActionController
|
|
34
33
|
|
35
34
|
def rewrite_path(options)
|
36
35
|
options = options.symbolize_keys
|
37
|
-
options.update((options[:params]).symbolize_keys)
|
36
|
+
options.update((options[:params] || {}).symbolize_keys)
|
38
37
|
RESERVED_OPTIONS.each {|k| options.delete k}
|
39
|
-
|
40
38
|
path, extras = Routing::Routes.generate(options, @request)
|
39
|
+
|
40
|
+
if extras[:overwrite_params]
|
41
|
+
params_copy = @request.parameters.delete_if { |k,v| ["controller","action"].include? k }
|
42
|
+
params_copy.update extras[:overwrite_params]
|
43
|
+
extras.delete(:overwrite_params)
|
44
|
+
extras.update(params_copy)
|
45
|
+
end
|
46
|
+
|
41
47
|
path = "/#{path.join('/')}".chomp '/'
|
42
48
|
path = '/' if path.empty?
|
43
49
|
path += build_query_string(extras)
|
@@ -45,46 +51,6 @@ module ActionController
|
|
45
51
|
return path
|
46
52
|
end
|
47
53
|
|
48
|
-
def action_name(options, action_prefix = nil, action_suffix = nil)
|
49
|
-
ensure_slash_suffix(options, :action_prefix)
|
50
|
-
ensure_slash_prefix(options, :action_suffix)
|
51
|
-
|
52
|
-
prefix = options[:action_prefix] || action_prefix || ""
|
53
|
-
suffix = options[:action] == "index" ? "" : (options[:action_suffix] || action_suffix || "")
|
54
|
-
name = (options[:action] == "index" ? "" : options[:action]) || ""
|
55
|
-
|
56
|
-
return prefix + name + suffix
|
57
|
-
end
|
58
|
-
|
59
|
-
def controller_name(options, controller_prefix)
|
60
|
-
ensure_slash_suffix(options, :controller_prefix)
|
61
|
-
|
62
|
-
controller_name = case options[:controller_prefix]
|
63
|
-
when String: options[:controller_prefix]
|
64
|
-
when false : ""
|
65
|
-
when nil : controller_prefix || ""
|
66
|
-
end
|
67
|
-
|
68
|
-
controller_name << (options[:controller] + "/") if options[:controller]
|
69
|
-
return controller_name
|
70
|
-
end
|
71
|
-
|
72
|
-
def path_params_in_list(options)
|
73
|
-
options[:path_params].inject("") { |path, pair| path += "/#{pair.last}" }
|
74
|
-
end
|
75
|
-
|
76
|
-
def ensure_slash_suffix(options, key)
|
77
|
-
options[key] = options[key] + "/" if options[key] && !options[key].empty? && options[key][-1..-1] != "/"
|
78
|
-
end
|
79
|
-
|
80
|
-
def ensure_slash_prefix(options, key)
|
81
|
-
options[key] = "/" + options[key] if options[key] && !options[key].empty? && options[key][0..1] != "/"
|
82
|
-
end
|
83
|
-
|
84
|
-
def include_id_in_path_params(options)
|
85
|
-
options[:path_params] = (options[:path_params] || {}).merge({"id" => options[:id]}) if options[:id]
|
86
|
-
end
|
87
|
-
|
88
54
|
# Returns a query string with escaped keys and values from the passed hash. If the passed hash contains an "id" it'll
|
89
55
|
# be added as a path element instead of a regular parameter pair.
|
90
56
|
def build_query_string(hash)
|
@@ -0,0 +1,79 @@
|
|
1
|
+
module ActionController #:nodoc:
|
2
|
+
|
3
|
+
# This module provides a class-level method for specifying that certain
|
4
|
+
# actions are guarded against being called without certain prerequisites
|
5
|
+
# being met. This is essentially a special kind of before_filter.
|
6
|
+
#
|
7
|
+
# An action may be guarded against being invoked without certain request
|
8
|
+
# parameters being set, or without certain session values existing.
|
9
|
+
#
|
10
|
+
# When a verification is violated, values may be inserted into the flash, and
|
11
|
+
# a specified redirection is triggered.
|
12
|
+
#
|
13
|
+
# Usage:
|
14
|
+
#
|
15
|
+
# class GlobalController < ActionController::Base
|
16
|
+
# # prevent the #update_settings action from being invoked unless
|
17
|
+
# # the 'admin_privileges' request parameter exists.
|
18
|
+
# verify :params => "admin_privileges", :only => :update_post,
|
19
|
+
# :redirect_to => { :action => "settings" }
|
20
|
+
#
|
21
|
+
# # disallow a post from being updated if there was no information
|
22
|
+
# # submitted with the post, and if there is no active post in the
|
23
|
+
# # session, and if there is no "note" key in the flash.
|
24
|
+
# verify :params => "post", :session => "post", "flash" => "note",
|
25
|
+
# :only => :update_post,
|
26
|
+
# :add_flash => { "alert" => "Failed to create your message" },
|
27
|
+
# :redirect_to => :category_url
|
28
|
+
#
|
29
|
+
module Verification
|
30
|
+
def self.append_features(base) #:nodoc:
|
31
|
+
super
|
32
|
+
base.extend(ClassMethods)
|
33
|
+
end
|
34
|
+
|
35
|
+
module ClassMethods
|
36
|
+
# Verify the given actions so that if certain prerequisites are not met,
|
37
|
+
# the user is redirected to a different action. The +options+ parameter
|
38
|
+
# is a hash consisting of the following key/value pairs:
|
39
|
+
#
|
40
|
+
# * <tt>:params</tt>: a single key or an array of keys that must
|
41
|
+
# be in the @params hash in order for the action(s) to be safely
|
42
|
+
# called.
|
43
|
+
# * <tt>:session</tt>: a single key or an array of keys that must
|
44
|
+
# be in the @session in order for the action(s) to be safely called.
|
45
|
+
# * <tt>:flash</tt>: a single key or an array of keys that must
|
46
|
+
# be in the flash in order for the action(s) to be safely called.
|
47
|
+
# * <tt>:add_flash</tt>: a hash of name/value pairs that should be merged
|
48
|
+
# into the session's flash if the prerequisites cannot be satisfied.
|
49
|
+
# * <tt>:redirect_to</tt>: the redirection parameters to be used when
|
50
|
+
# redirecting if the prerequisites cannot be satisfied.
|
51
|
+
# * <tt>:only</tt>: only apply this verification to the actions specified in
|
52
|
+
# the associated array (may also be a single value).
|
53
|
+
# * <tt>:except</tt>: do not apply this verification to the actions specified in
|
54
|
+
# the associated array (may also be a single value).
|
55
|
+
def verify(options={})
|
56
|
+
filter_opts = { :only => options[:only], :except => options[:except] }
|
57
|
+
before_filter(filter_opts) do |c|
|
58
|
+
c.send :verify_action, options
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def verify_action(options) #:nodoc:
|
64
|
+
prereqs_invalid =
|
65
|
+
[*options[:params] ].find { |v| @params[v].nil? } ||
|
66
|
+
[*options[:session]].find { |v| @session[v].nil? } ||
|
67
|
+
[*options[:flash] ].find { |v| flash[v].nil? }
|
68
|
+
|
69
|
+
if prereqs_invalid
|
70
|
+
flash.update(options[:add_flash]) if options[:add_flash]
|
71
|
+
redirect_to(options[:redirect_to])
|
72
|
+
return false
|
73
|
+
end
|
74
|
+
|
75
|
+
true
|
76
|
+
end
|
77
|
+
private :verify_action
|
78
|
+
end
|
79
|
+
end
|