Skip to content

Commit 8eac38f

Browse files
committed
Extract module and tests from rails
1 parent 11864ff commit 8eac38f

File tree

5 files changed

+459
-0
lines changed

5 files changed

+459
-0
lines changed

README

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
This module provides a class-level method for specifying that certain
2+
actions are guarded against being called without certain prerequisites
3+
being met. This is essentially a special kind of before_filter.
4+
5+
An action may be guarded against being invoked without certain request
6+
parameters being set, or without certain session values existing.
7+
8+
When a verification is violated, values may be inserted into the flash, and
9+
a specified redirection is triggered. If no specific action is configured,
10+
verification failures will by default result in a 400 Bad Request response.
11+
12+
Usage:
13+
14+
class GlobalController < ActionController::Base
15+
# Prevent the #update_settings action from being invoked unless
16+
# the 'admin_privileges' request parameter exists. The
17+
# settings action will be redirected to in current controller
18+
# if verification fails.
19+
verify :params => "admin_privileges", :only => :update_post,
20+
:redirect_to => { :action => "settings" }
21+
22+
# Disallow a post from being updated if there was no information
23+
# submitted with the post, and if there is no active post in the
24+
# session, and if there is no "note" key in the flash. The route
25+
# named category_url will be redirected to if verification fails.
26+
27+
verify :params => "post", :session => "post", "flash" => "note",
28+
:only => :update_post,
29+
:add_flash => { "alert" => "Failed to create your message" },
30+
:redirect_to => :category_url
31+
32+
Note that these prerequisites are not business rules. They do not examine
33+
the content of the session or the parameters. That level of validation should
34+
be encapsulated by your domain model or helper methods in the controller.

Rakefile

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
require 'rake'
2+
require 'rake/testtask'
3+
require 'rake/rdoctask'
4+
5+
desc 'Default: run unit tests.'
6+
task :default => :test
7+
8+
desc 'Test the verification plugin.'
9+
Rake::TestTask.new(:test) do |t|
10+
t.libs << 'lib'
11+
t.pattern = 'test/**/*_test.rb'
12+
t.verbose = true
13+
end
14+
15+
desc 'Generate documentation for the verification plugin.'
16+
Rake::RDocTask.new(:rdoc) do |rdoc|
17+
rdoc.rdoc_dir = 'rdoc'
18+
rdoc.title = 'Verification'
19+
rdoc.options << '--line-numbers' << '--inline-source'
20+
rdoc.rdoc_files.include('README')
21+
rdoc.rdoc_files.include('lib/**/*.rb')
22+
end

init.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
require 'action_controller/verification'

lib/action_controller/verification.rb

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
module ActionController #:nodoc:
2+
module Verification #:nodoc:
3+
extend ActiveSupport::Concern
4+
5+
include AbstractController::Callbacks, Flash, Rendering
6+
7+
# This module provides a class-level method for specifying that certain
8+
# actions are guarded against being called without certain prerequisites
9+
# being met. This is essentially a special kind of before_filter.
10+
#
11+
# An action may be guarded against being invoked without certain request
12+
# parameters being set, or without certain session values existing.
13+
#
14+
# When a verification is violated, values may be inserted into the flash, and
15+
# a specified redirection is triggered. If no specific action is configured,
16+
# verification failures will by default result in a 400 Bad Request response.
17+
#
18+
# Usage:
19+
#
20+
# class GlobalController < ActionController::Base
21+
# # Prevent the #update_settings action from being invoked unless
22+
# # the 'admin_privileges' request parameter exists. The
23+
# # settings action will be redirected to in current controller
24+
# # if verification fails.
25+
# verify :params => "admin_privileges", :only => :update_post,
26+
# :redirect_to => { :action => "settings" }
27+
#
28+
# # Disallow a post from being updated if there was no information
29+
# # submitted with the post, and if there is no active post in the
30+
# # session, and if there is no "note" key in the flash. The route
31+
# # named category_url will be redirected to if verification fails.
32+
#
33+
# verify :params => "post", :session => "post", "flash" => "note",
34+
# :only => :update_post,
35+
# :add_flash => { "alert" => "Failed to create your message" },
36+
# :redirect_to => :category_url
37+
#
38+
# Note that these prerequisites are not business rules. They do not examine
39+
# the content of the session or the parameters. That level of validation should
40+
# be encapsulated by your domain model or helper methods in the controller.
41+
module ClassMethods
42+
# Verify the given actions so that if certain prerequisites are not met,
43+
# the user is redirected to a different action. The +options+ parameter
44+
# is a hash consisting of the following key/value pairs:
45+
#
46+
# <tt>:params</tt>::
47+
# a single key or an array of keys that must be in the <tt>params</tt>
48+
# hash in order for the action(s) to be safely called.
49+
# <tt>:session</tt>::
50+
# a single key or an array of keys that must be in the <tt>session</tt>
51+
# in order for the action(s) to be safely called.
52+
# <tt>:flash</tt>::
53+
# a single key or an array of keys that must be in the flash in order
54+
# for the action(s) to be safely called.
55+
# <tt>:method</tt>::
56+
# a single key or an array of keys--any one of which must match the
57+
# current request method in order for the action(s) to be safely called.
58+
# (The key should be a symbol: <tt>:get</tt> or <tt>:post</tt>, for
59+
# example.)
60+
# <tt>:xhr</tt>::
61+
# true/false option to ensure that the request is coming from an Ajax
62+
# call or not.
63+
# <tt>:add_flash</tt>::
64+
# a hash of name/value pairs that should be merged into the session's
65+
# flash if the prerequisites cannot be satisfied.
66+
# <tt>:add_headers</tt>::
67+
# a hash of name/value pairs that should be merged into the response's
68+
# headers hash if the prerequisites cannot be satisfied.
69+
# <tt>:redirect_to</tt>::
70+
# the redirection parameters to be used when redirecting if the
71+
# prerequisites cannot be satisfied. You can redirect either to named
72+
# route or to the action in some controller.
73+
# <tt>:render</tt>::
74+
# the render parameters to be used when the prerequisites cannot be satisfied.
75+
# <tt>:only</tt>::
76+
# only apply this verification to the actions specified in the associated
77+
# array (may also be a single value).
78+
# <tt>:except</tt>::
79+
# do not apply this verification to the actions specified in the associated
80+
# array (may also be a single value).
81+
def verify(options={})
82+
before_filter :only => options[:only], :except => options[:except] do
83+
verify_action options
84+
end
85+
end
86+
end
87+
88+
private
89+
90+
def verify_action(options) #:nodoc:
91+
if prereqs_invalid?(options)
92+
flash.update(options[:add_flash]) if options[:add_flash]
93+
response.headers.merge!(options[:add_headers]) if options[:add_headers]
94+
apply_remaining_actions(options) unless performed?
95+
end
96+
end
97+
98+
def prereqs_invalid?(options) # :nodoc:
99+
verify_presence_of_keys_in_hash_flash_or_params(options) ||
100+
verify_method(options) ||
101+
verify_request_xhr_status(options)
102+
end
103+
104+
def verify_presence_of_keys_in_hash_flash_or_params(options) # :nodoc:
105+
[*options[:params] ].find { |v| v && params[v.to_sym].nil? } ||
106+
[*options[:session]].find { |v| session[v].nil? } ||
107+
[*options[:flash] ].find { |v| flash[v].nil? }
108+
end
109+
110+
def verify_method(options) # :nodoc:
111+
[*options[:method]].all? { |v| request.method != v.to_sym } if options[:method]
112+
end
113+
114+
def verify_request_xhr_status(options) # :nodoc:
115+
request.xhr? != options[:xhr] unless options[:xhr].nil?
116+
end
117+
118+
def apply_redirect_to(redirect_to_option) # :nodoc:
119+
(redirect_to_option.is_a?(Symbol) && redirect_to_option != :back) ? self.__send__(redirect_to_option) : redirect_to_option
120+
end
121+
122+
def apply_remaining_actions(options) # :nodoc:
123+
case
124+
when options[:render] ; render(options[:render])
125+
when options[:redirect_to] ; redirect_to(apply_redirect_to(options[:redirect_to]))
126+
else head(:bad_request)
127+
end
128+
end
129+
end
130+
end
131+
132+
ActionController::Base.send :include, ActionController::Verification

0 commit comments

Comments
 (0)