Below is a proc that's useful for an app I'm working on that relies heavily on index.vuh routing.
Imagine that you have a url, /foo/123, where id=123.
index.vuh might say:
rp_form_put id $id
rp_internal_redirect /some/template/somewhere
Now imagine that somewhere we redirect to /foo/123, for example from ad_form, or after logging in, or from a url generated by ad_return_url. ad_return_url will generate the url /foo/123?id=123, which causes problems with ad_page_contract (which sees two instances of the id parameter).
The proc is called in index.vuh instead of rp_form_put and rp_internal_redirect. If it sees something like /foo/123?id=123, it redirects to /foo/123 (but keeps any other parameters).
It's invoked like this:
um::url::internal_redirect -template foo -params {id}
or
um::url::internal_redirect -template foo -params {foo {bar $value}}
(This is the syntax of export_vars.) Ideally OpenACS should have a proc like this, and it should set a global variable with the names of parameters set with rp_form_put so ad_return_url doesn't include them. Or there should be an explanation of the Right Way to use index.vuh.
ad_proc -public um::url::internal_redirect { -return:boolean
-template:required
{-params ""} } {
Only used in /www/*.vuh. Performs an internal redirect.
If params are present in the form parameters, we may call
ad_returnredirect
and not return.
@author Guan Yang (guan@unicast.org)
@creation-date 2005-03-28
@see export_vars
@see ad_returnredirect
@see rp_internal_redirect
@see ad_script_abort
@param params Parameters in a syntax similar to export_vars
.
@param return Returns. Otherwise we will call
ad_script_abort
. Note that we will never return if it is
necessary to perform a redirect.
@param template The template to return.
} {
set url [ad_conn url]
set export_spec [list]
set params_for_export [list]
# Fetch the parameters
foreach param $params {
set len [llength $param]
if { $len != 1 && $len != 2 } { continue }
if { $len == 2 } {
set param_name [lindex $param 0]
set param_value [lindex $param 1]
# We do a subst in caller's stack
upvar __um__url__internal_redirect__value up_value
set up_value $param_value
uplevel {
set __um__url__internal_redirect__subst \
[subst $__um__url__internal_redirect__value]
}
upvar __um__url__internal_redirect__subst up_substed_value
set param_value $up_substed_value
# Clean up in caller's stack
unset up_value up_substed_value
lappend params_for_export $param_name
lappend export_spec [list $param_name $param_value]
} else {
set param_name $param
upvar $param_name param_value
if { ![info exists param_value] } { continue }
lappend params_for_export $param_name
lappend export_spec [list $param_name $param_value]
}
}
# Remove parameters from the existing form
set form [rp_getform]
set deleted 0
foreach param $params_for_export {
set matches [lsearch -all -exact [ad_ns_set_keys $form] $param]
foreach match $matches {
incr deleted
ns_set delete $form $match
}
}
# If we deleted anything from the form, perform a redirect
if { $deleted > 0 } {
# We need to retain everything in the existing form
# The form has already been pruned of offending params above
set form_spec [list]
# Repack array format into export_vars format
set form_array [ns_set array $form]
for { set i 0 } { $i < [llength $form_array] } { incr i } {
lappend form_spec [list [lindex $form_array $i] \
[lindex $form_array [incr i]]]
}
ad_returnredirect [export_vars -base $url $form_spec]
ad_script_abort
}
# Now set the form vars and do an internal redirect
foreach param $export_spec {
rp_form_put [lindex $param 0] [lindex $param 1]
}
rp_internal_redirect $template
if { !$return_p } {
ad_script_abort
}
}