Here's a common Web application workflow. A user gets to a page. He doesn't have access to the page because he isn't logged in. He gets redirected to the login page. He logs in. Perhaps he even has to create an account first. Afterwards, he gets redirected to the page he was trying to go to in the first place. Users find this sort of behavior helpful.
Here's another. The user is trying to buy something. He gets redirected to Google checkout (disclaimer: I've never used Google checkout). After he finishes checking out, he gets redirected back to the origin site. Perhaps he now has access to download the thing he just bought.
Thanks to the authlogic tutorial, I already had code to take care of the login workflow. However, I now find myself needing to do more workflows like it. The user tries to go to a page. However, he must do this other thing. Afterwards, he can go to the original page. What's the best way to handle the problem generically?
Here are the constraints that come to mind. I don't want two workflows stepping on each others toes. (I'm not even sure workflows have toes!) Hence, if one workflow leads to a page, and then the user has to do another workflow, he should get redirected at the end of the inner workflow and then get redirected at the end of the outer workflow. However, I don't expect that the user will need to recurse. That is, I don't expect one workflow to lead to itself again in a recursive sort of way.
With all that in mind, I took what authlogic gave me and expanded on it. In my base class, ApplicationController, I have:
Here's another. The user is trying to buy something. He gets redirected to Google checkout (disclaimer: I've never used Google checkout). After he finishes checking out, he gets redirected back to the origin site. Perhaps he now has access to download the thing he just bought.
Thanks to the authlogic tutorial, I already had code to take care of the login workflow. However, I now find myself needing to do more workflows like it. The user tries to go to a page. However, he must do this other thing. Afterwards, he can go to the original page. What's the best way to handle the problem generically?
Here are the constraints that come to mind. I don't want two workflows stepping on each others toes. (I'm not even sure workflows have toes!) Hence, if one workflow leads to a page, and then the user has to do another workflow, he should get redirected at the end of the inner workflow and then get redirected at the end of the outer workflow. However, I don't expect that the user will need to recurse. That is, I don't expect one workflow to lead to itself again in a recursive sort of way.
With all that in mind, I took what authlogic gave me and expanded on it. In my base class, ApplicationController, I have:
protectedHere's how to use it to handle the login case:
def store_location(session_key_suffix, url=request.request_uri)
session[session_key_for_return_to(session_key_suffix)] = url
end
def redirect_back_or_default(session_key_suffix, default)
key = session_key_for_return_to(session_key_suffix)
redirect_to(session[key] || default)
session[key] = nil
end
def location_stored?(session_key_suffix)
session.has_key?(session_key_for_return_to(session_key_suffix))
end
private
def session_key_for_return_to(session_key_suffix)
"return_to_#{session_key_suffix.to_s}".to_sym
end
def require_userAfter the user logs in, I call:
unless current_user
store_location(:after_login)
flash[:error_message] = "You must be logged in to access this page"
redirect_to new_user_session_url
return false
end
end
redirect_back_or_default(:after_login, root_url)Based on my tests, the above works. It can handle nested workflows. It can even handle a user working on two different workflows in two different tabs. I can envision some esoteric ways to mess the above code up, but I'm going to give it a couple weeks and see how it turns out in practice.
Comments
So call "login/?return_to=comment" and get username and password from the user but pass in "comment" as the place we want to come back to.
I'm new to programming but that seems to work pretty well.