Assert yourself, man! -- redirecting with RJS
Courtenay : February 19th, 2006
Got an ajax method that degrades but want to redirect? Ever tried sending a redirect with ajax? It either crashes, breaks, or just doesn't work.
Here's the solution, and as a bonus, a new test method to test your redirects.
def new
if request.xhr?
render :update { |page| page.redirect_to :action => 'create' }
else
redirect_to(:action => 'create')
end
end
render :update is the infamous RJS call, wherein it returns a document with text/javascript content-type. If you look into prototype.js, it automagically evals such documents. The response body will be pure javascript, baby, and it'll look something like 'window.location.href = "/whatever/do/5"'
Here's the test helper to test if your ajax response is actually called. I'd love for someone to rewrite this, write some tests, and submit it as a patch to rails.. Hi, lazyweb!
In the mean time, you can just dump it in test/test_helper.rb
def assert_js_redirected_to(options={}, message=nil)
clean_backtrace do
assert_response(:success, message)
assert_equal 'text/javascript', @response.headers['Content-Type'], 'Response should be Javascript content-type';
js_regexp = %r{(\w+://)?.*?(/|$|\\\?)(.*)}
url_regexp = %r{^window\.location\.href [=] ['"]#{js_regexp}['"][;]$}
redirected_to = @response.body.match(url_regexp)
assert_not_nil(redirected_to, message)
redirected_to = redirected_to[3]
msg = build_message(message, "expected a JS redirect to >, found one to >", options, redirected_to)
if options.is_a?(String)
assert_equal(options.gsub(/^\//, ''), redirected_to, message)
else
msg = build_message(message, "response is not a redirection to all of the options supplied (redirection is >)", redirected_to)
assert_equal(@controller.url_for(options).match(js_regexp)[3], redirected_to, msg)
end
end
end
Strip the ^ and $ from that regex if you're returning more than just a URL in your RJS update call.
*update*
fixed the method so it actually takes a hash. testing is not just for sissies!
2 Responses to “Assert yourself, man! -- redirecting with RJS”
Leave a Reply
Remember: escape your underscores \_ and indent code at least 4 spaces or incur the wrath of smartypants.
June 25th, 2007 at 08:57 PM
Not sure if I did something wrong with your example but here’s what works for me:
if request.xhr? render :update do |page| page.redirectto loginurl end else redirect_to(:action => ‘create’) end
October 22nd, 2007 at 05:37 AM
Hi,
Thank you, man! I was just trying to implement this myself, but I though "Some very clever guy must have done this before me", and I googled for it. Just one minor modification to the fourth line:
assert_match(/text\/javascript/, @response.headers['Content-Type'], 'Response should be Javascript content-type')
That is because you can have some other things in the content type header, like "text/javascript; charset=utf-8"
Regards, Sergio Fierens.