forked from rails/rails
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added Verifications that allows you to specify preconditions to actio…
…ns 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. rails#897 [Jamis Buck] git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@1008 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
- Loading branch information
Showing
4 changed files
with
220 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
module ActionController #:nodoc: | ||
|
||
# This module provides a class-level method for specifying that certain | ||
# actions are guarded against being called without certain prerequisites | ||
# being met. This is essentially a special kind of before_filter. | ||
# | ||
# An action may be guarded against being invoked without certain request | ||
# parameters being set, or without certain session values existing. | ||
# | ||
# When a verification is violated, values may be inserted into the flash, and | ||
# a specified redirection is triggered. | ||
# | ||
# Usage: | ||
# | ||
# class GlobalController < ActionController::Base | ||
# # prevent the #update_settings action from being invoked unless | ||
# # the 'admin_privileges' request parameter exists. | ||
# verify :params => "admin_privileges", :only => :update_post | ||
# :redirect_to => { :action => "settings" } | ||
# | ||
# # disallow a post from being updated if there was no information | ||
# # submitted with the post, and if there is no active post in the | ||
# # session, and if there is no "note" key in the flash. | ||
# verify :params => "post", :session => "post", "flash" => "note", | ||
# :only => :update_post, | ||
# :add_flash => { "alert" => "Failed to create your message" }, | ||
# :redirect_to => :category_url | ||
# | ||
module Verification | ||
def self.append_features(base) #:nodoc: | ||
super | ||
base.extend(ClassMethods) | ||
end | ||
|
||
module ClassMethods | ||
# Verify the given actions so that if certain prerequisites are not met, | ||
# the user is redirected to a different action. The +options+ parameter | ||
# is a hash consisting of the following key/value pairs: | ||
# | ||
# * <tt>:params</tt>: a single key or an array of keys that must | ||
# be in the @params hash in order for the action(s) to be safely | ||
# called. | ||
# * <tt>:session</tt>: a single key or an array of keys that must | ||
# be in the @session in order for the action(s) to be safely called. | ||
# * <tt>:flash</tt>: a single key or an array of keys that must | ||
# be in the flash in order for the action(s) to be safely called. | ||
# * <tt>:add_flash</tt>: a hash of name/value pairs that should be merged | ||
# into the session's flash if the prerequisites cannot be satisfied. | ||
# * <tt>:redirect_to</tt>: the redirection parameters to be used when | ||
# redirecting if the prerequisites cannot be satisfied. | ||
# * <tt>:only</tt>: only apply this verification to the actions specified in | ||
# the associated array (may also be a single value). | ||
# * <tt>:except</tt>: do not apply this verification to the actions specified in | ||
# the associated array (may also be a single value). | ||
def verify(options={}) | ||
filter_opts = { :only => options[:only], :except => options[:except] } | ||
before_filter(filter_opts) do |c| | ||
c.send :verify_action, options | ||
end | ||
end | ||
end | ||
|
||
def verify_action(options) #:nodoc: | ||
prereqs_invalid = | ||
[*options[:params] ].find { |v| @params[v].nil? } || | ||
[*options[:session]].find { |v| @session[v].nil? } || | ||
[*options[:flash] ].find { |v| flash[v].nil? } | ||
|
||
if prereqs_invalid | ||
flash.update(options[:add_flash]) if options[:add_flash] | ||
redirect_to(options[:redirect_to]) | ||
return false | ||
end | ||
|
||
true | ||
end | ||
private :verify_action | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,137 @@ | ||
require File.dirname(__FILE__) + '/../abstract_unit' | ||
|
||
class VerificationTest < Test::Unit::TestCase | ||
class TestController < ActionController::Base | ||
verify :only => :guarded_one, :params => "one", | ||
:redirect_to => { :action => "unguarded" } | ||
|
||
verify :only => :guarded_two, :params => %w( one two ), | ||
:redirect_to => { :action => "unguarded" } | ||
|
||
verify :only => :guarded_with_flash, :params => "one", | ||
:add_flash => { "notice" => "prereqs failed" }, | ||
:redirect_to => { :action => "unguarded" } | ||
|
||
verify :only => :guarded_in_session, :session => "one", | ||
:redirect_to => { :action => "unguarded" } | ||
|
||
verify :only => [:multi_one, :multi_two], :session => %w( one two ), | ||
:redirect_to => { :action => "unguarded" } | ||
|
||
def guarded_one | ||
render_text "#{@params["one"]}" | ||
end | ||
|
||
def guarded_with_flash | ||
render_text "#{@params["one"]}" | ||
end | ||
|
||
def guarded_two | ||
render_text "#{@params["one"]}:#{@params["two"]}" | ||
end | ||
|
||
def guarded_in_session | ||
render_text "#{@session["one"]}" | ||
end | ||
|
||
def multi_one | ||
render_text "#{@session["one"]}:#{@session["two"]}" | ||
end | ||
|
||
def multi_two | ||
render_text "#{@session["two"]}:#{@session["one"]}" | ||
end | ||
|
||
def unguarded | ||
render_text "#{@params["one"]}" | ||
end | ||
end | ||
|
||
def setup | ||
@controller = TestController.new | ||
@request = ActionController::TestRequest.new | ||
@response = ActionController::TestResponse.new | ||
end | ||
|
||
def test_guarded_one_with_prereqs | ||
process "guarded_one", "one" => "here" | ||
assert_equal "here", @response.body | ||
end | ||
|
||
def test_guarded_one_without_prereqs | ||
process "guarded_one" | ||
assert_redirected_to :action => "unguarded" | ||
end | ||
|
||
def test_guarded_with_flash_with_prereqs | ||
process "guarded_with_flash", "one" => "here" | ||
assert_equal "here", @response.body | ||
assert_flash_empty | ||
end | ||
|
||
def test_guarded_with_flash_without_prereqs | ||
process "guarded_with_flash" | ||
assert_redirected_to :action => "unguarded" | ||
assert_flash_equal "prereqs failed", "notice" | ||
end | ||
|
||
def test_guarded_two_with_prereqs | ||
process "guarded_two", "one" => "here", "two" => "there" | ||
assert_equal "here:there", @response.body | ||
end | ||
|
||
def test_guarded_two_without_prereqs_one | ||
process "guarded_two", "two" => "there" | ||
assert_redirected_to :action => "unguarded" | ||
end | ||
|
||
def test_guarded_two_without_prereqs_two | ||
process "guarded_two", "one" => "here" | ||
assert_redirected_to :action => "unguarded" | ||
end | ||
|
||
def test_guarded_two_without_prereqs_both | ||
process "guarded_two" | ||
assert_redirected_to :action => "unguarded" | ||
end | ||
|
||
def test_unguarded_with_params | ||
process "unguarded", "one" => "here" | ||
assert_equal "here", @response.body | ||
end | ||
|
||
def test_unguarded_without_params | ||
process "unguarded" | ||
assert_equal "", @response.body | ||
end | ||
|
||
def test_guarded_in_session_with_prereqs | ||
process "guarded_in_session", {}, "one" => "here" | ||
assert_equal "here", @response.body | ||
end | ||
|
||
def test_guarded_in_session_without_prereqs | ||
process "guarded_in_session" | ||
assert_redirected_to :action => "unguarded" | ||
end | ||
|
||
def test_multi_one_with_prereqs | ||
process "multi_one", {}, "one" => "here", "two" => "there" | ||
assert_equal "here:there", @response.body | ||
end | ||
|
||
def test_multi_one_without_prereqs | ||
process "multi_one" | ||
assert_redirected_to :action => "unguarded" | ||
end | ||
|
||
def test_multi_two_with_prereqs | ||
process "multi_two", {}, "one" => "here", "two" => "there" | ||
assert_equal "there:here", @response.body | ||
end | ||
|
||
def test_multi_two_without_prereqs | ||
process "multi_two" | ||
assert_redirected_to :action => "unguarded" | ||
end | ||
end |