How to properly set cache.action parameters in order to have different cache for logged-in and not?

42 views
Skip to first unread message

Lisandro

unread,
Jun 6, 2016, 9:26:35 AM6/6/16
to web2py-users
I need to decorate a controller function with @cache.action in order to have two different versions of the rendered view: one for logged-in users and another one for not logged-in users.

Notice that I don't need one different caché for each user (that could be achieved using session argument). 
Instead, what I need is two versions of the rendered view: one for all the users that aren't logged-in, and one for all the users that are logged-in.
The only difference between those two versions of the rendered view is that one of them includes a top navbar, which is is the same for all logged-in users, but it shouldn't be present in the cache version for not logged-in users.


Because I need the same behaviour in several controller functions, the way I do it is defining the @cache.action parameters at the models level, like this:

CACHE = Storage()
CACHE
.prefix = ''
CACHE
.time_expire = 300
CACHE
.public = True
CACHE
.session = False
CACHE
.vars = False
if auth.is_logged_in():
    CACHE
.prefix += 'logged-in-'
    CACHE
.public = False
   
# CACHE.model = None


The I use that configuration in controller functions:

@cache.action(time_expire=CACHE.time_expire, cache_model=CACHE.model, session=CACHE.session, vars=CACHE.vars, public=CACHE.public, prefix=CACHE.prefix)
def index():
   
return response.render(...)


@cache.action(time_expire=CACHE.time_expire, cache_model=CACHE.model, session=CACHE.session, vars=CACHE.vars, public=CACHE.public, prefix=CACHE.prefix)
def forum():
   
return response.render(...)



However, I'm having trouble to make it work as I want. 
It's not working entirely wrong, but the problem is this:
  1) the user hits the index, without being logged-in;
  2) the user logs in
  3) the user goes back to index, but still sees the cached page (I think it's the browser that is using local cache). If the user reloads the page (hitting F5 or Ctrl+R), then the new view is shown.


What am I missing?

As you can see in the code, I've tried:
 - setting public=False regardless of the logged in state;
 - setting cache.model=None when the user is logged-in;
 - using a different prefix for logged in users;

But the problem remains: after logging in, the user need to hit F5 in order to see the other view.


As always, I will appreciate any help on this.
Regards, Lisandro

Lisandro

unread,
Jun 6, 2016, 1:10:51 PM6/6/16
to web2py-users
I've been doing some more test and a bit more reading about this, and I can see (if I'm not wrong) that this is not a problem, it's the expected behaviour.
@cache.action does precisely that: it sets cache headers for client-side caching, that is, browser side caching. 
And, optionally, it allows you to set server-cache also (using a cache.model, like ram, disk or redis).

So, using @cache.action, the user (without being logged) visits a page and the browser stores the view in cache. 
Then the user logs in, and returns to the previously visited page, and the browser uses the copy in local caché.

I've read that I could use the old (but still perfectly valid) method of @cache decorator.
However @cache.action has some facilities to handle vars and session. wich aren't present with @cache


The whole point of this was to avoid an extra ajax call from the views.
I was using the same cached view for all users, and the HTML returned to the browser had an ajax call that loaded the user menu. 
However. this meant that the models were executed twice per every page visit, and that wasn't very good, also I'm trying to save CPU.

I'll try to figure out if there is an alternative.

Niphlod

unread,
Jun 6, 2016, 6:01:27 PM6/6/16
to web2py-users
it's kinda chicken-and-egg here, because your real trouble is that the unlogged user hits a page that you want to be cached client-side as long as he is not logged in.
if you let it cache client-side, having the user returning to the same page to expect a different outcome is impossible. 
IMHO the solution is that you should refactor your app to present a proper "landing page" uri for public viewers and a separate one for logged in users. 

Lisandro

unread,
Jun 7, 2016, 11:59:12 AM6/7/16
to web2py-users
After reconsidering the whole thing, I've found a way to achieve what I wanted, without having to change too much code.

Considering that I needed to keep client-side caching, the only way to go was redirecting the user to a "different URL".
So I used a lazy argument: when the user logs in, he is redirected to the previous URL where he was, but with a lazy argument at the end of the URL. 
This way, the browser sees a different URL, and it doesn't use the local cache.

Because of the "log in" link is in every page of the template, I had to consider the args and vars that could already be in the current path.
So, in the template the login link is created like this:

{{
_args
= request.args
if 'l' not in _args:
    _args
.append('l')
pass
login_url
= URL('default', 'user', args='login', vars={'_next':URL(args=_args, vars=request.get_vars)})
}}
<a href="{{=login_url}}">Log in</a>

Then of course, the function in charge of logging in the user redirects him to the URL received in request.vars._next

In my models:

# Setup cache.action arguments

CACHE
.time_expire = 300
CACHE
.public = True
CACHE
.session = False
CACHE
.vars = False

# if the user is logged in, setup different cache.action arguments
if auth.is_logged_in():
    CACHE
.prefix = 'plantel-'
    CACHE
.time_expire = 1
    CACHE
.model = None

This way is working like a charm, and I was able to save an additional extra request just to load a topnavbar.
Although, this is not bullet proof: the user may still clic a link to a page that is in his local cache, so there is no way to avoid that.
For this case and what I needed, the solution is acceptable.


As always, thankyou very much Niphlod for your time.
I wanted to post my solution just in case someone needs to deal with a similar situation.

Regards, Lisandro.
Reply all
Reply to author
Forward
0 new messages