Using SessionTimeout: which actions need session data?

All,

I’ve successfully implemented SessionTimeout. It works great.

On a given request, assuming that the session has timed out, what I’d
like to do is have my session timeout handler be smart enough to
determine which actions in my app. actually require session data in
order to function correctly vs. actions which don’t require session
data.

Then the handler can redirect to the original requested action IF it
DOESN’T require the use of session data. IF the original requested
action DOES require the use of pre-existing session data, then the
handler would redirect to some predefined “restarting” action.

Obviously, I know my app. and I can specify which actions are in which
camp via hard coding etc. Not a problem. However, it would be nice to
be able to determine this in some more generic way. The most generic
rule for figuring out the disposition of a given action would seem to
be:

IF the contents of an action contain any assignment statement (or return
value) that includes a reference to a session hash member (e.g. x =
session[:blah]), then this action requires pre-existing session data and
cannot be safely redirected to after a session timeout. Otherwise, (no
assignment or return statements that reference a session hash member),
the action is safe to be redirected to after a session timeout.

Can anyone think of a clever way to encapsulate a generic test for this?

If a fully generic test can’t be created, one way to handle this could
be to maintain lists of “safe-to-redirect-to” vs.
“unsafe-to-redirect-to” methods in each controller and then just
interrogate the controllers to figure it out in the session timeout
handler.

Thanks,
Wes

I would handle this using two separate before_filter actions. For
example,

before_filter expire_session
before_filter authenticate

expire_session - if expired reset_session
authenticate - check session for some defined value (e.g.
session[:user]) and
act depending on whether value is initialized.

For controllers that don’t require session, don’t add the filter. For
actions
that don’t require session, use except => [ :action1, :action2, …]
along with
the filter.

I am not sure you will gain anything trying to detect whether an action
requires
session or not, besides complexity.

HTH,

– Long
http://MeandmyCity.com/ - Free online business directory for local
communities
http://edgesoft.ca/blog/read/2 - No-Cookie Session Support plugin for
Rails

Long,

Thanks, but that isn’t quite what I want. I want the session to expire
after a specific time between consecutive requests, regardless of which
action is requested. Your proposal would seem to tie session expiry to
a particular set of actions.

Wes

Perhaps I misunderstood your question.

A session expires after a period of inactivity. The next request will
kick
start the expiring process in the expire_session filter. I believe this
action
should just perform house cleaning, reset_session and return true
(always).

The authenticate filter runs next. It may check like

if !session[:user] then
redirect_to ‘login’
return false
end

Note here the before filters will run before control is passed to the
requested action, whatever that may be. Though, you can control
which action the filters will affect by using either except => [] or
only => [] options.

I hope I am talking about the same thing you are. If not sorry I can’t
help.

Cheers,

– Long

----- Original Message -----
From: “Wes G.”

Long wrote:

Perhaps I misunderstood your question.

A session expires after a period of inactivity. The next request will
kick
start the expiring process in the expire_session filter. I believe this
action
should just perform house cleaning, reset_session and return true
(always).

The authenticate filter runs next. It may check like

if !session[:user] then
redirect_to ‘login’
return false
end

Long,

I understand all of that.

I’d like to point out that in my case, my session timeout callback
method attempts to redirect_to somewhere no matter what. I have to
always return false from it because everything I have is protected by
my authenticate filter. Since I would have a new session (created by
session_timeout) and no session[:user], I would get a double
render/redirect error if the session timeout callback returned true and
allowed the authenticate filter to run.

My question was about making an intelligent decision about which action
to redirect_to within the session timeout callback.

Wes

Wes G. wrote:

Long,

I understand all of that.

Alright.

I’d like to point out that in my case, my session timeout callback
method attempts to redirect_to somewhere no matter what. I have to
always return false from it because everything I have is protected by
my authenticate filter. Since I would have a new session (created by
session_timeout) and no session[:user], I would get a double
render/redirect error if the session timeout callback returned true and
allowed the authenticate filter to run.

The double render/redirect error is precisely why I keep the
expire_session
filter simple. No render/redirect whatsoever. I leave it to filters down
the
chain (like authenticate) to pick up on the fact that the session have
expired
and do something with it.

My question was about making an intelligent decision about which action
to redirect_to within the session timeout callback.

I was trying to say this isn’t necessary if you leave that decission to
the
down chain filters, like authenticate. That would be my approach and
I do appologize for not being more helpful.

Regards,

– Long

I ended up doing the following:

In application.rb:

session_times_out_in 4.hours, :after_timeout => :handle_session_timeout,
:except => :handle_session_timeout

handle_session_timeout is a protected method in application.rb:

def handle_session_timeout
session[:session_expiry_notice] = ‘You have been inactive for too
long, and your session has expired.’
requested_controller_class = (controller_name.camelize +
‘Controller’).constantize
if
requested_controller_class.respond_to?(‘session_data_not_needed_by?’) &&
requested_controller_class.session_data_not_needed_by?(action_name,
params.reject {|key, value| [‘action’, ‘controller’].include?(key)})
redirect_to({:controller => controller_name, :action =>
action_name}.merge(params))
else
redirect_to(:controller => ‘general’, :action =>
‘display_open_items’)
end
return false
end

handle_session_timeout always returns false to ensure that a double
render/redirect doesn’t occur.

Each controller that contains any methods which do not require session
data to be available in order to function properly has a class method
like the following:

def self.session_data_not_needed_by?(action_name, params)
[‘start_quote’, ‘display_quotes’].include?(action_name) ||
(action_name == ‘requote’ && (! params.empty?))
end

Basically, when the session expires, we figure out if the action can
proceed normally (based on the session_data_not_needed_by? method) and
if so, we proceed. Otherwise, we go to a predefined “default” action
where the user can start over (in this case general/display_open_items).

Long,

That makes sense.

I am attempting to send people back to where they wanted to go when I
can do that
from the timeout callback. I have this working. But I
realize that I could probably set it up so that the authenticate filter
handles that.

I think my approach is clean in the sense that the authenticate filter
is still only responsible for authenticating and doesn’t need to be
concerned about “doing the work” of the session timeout callback.

Thanks for all the help,
Wes