简体   繁体   中英

How do I manage the current user session on the client side?

I have a web app which is part Rails and part Backbone . Some things such as a commenting system I have implemented are written mostly in Javascript on the client side. The Rails backend simply handles persistance by passing JSON back and forth.

When I render pages from the server, handling who gets to see what is easy. I can say things such as

<li class="comment">
  <span class="comment_text"><%= @comment.text %></span>
  <% if user_signed_in? and current_user == @comment.author %>
    <a class="delete" href="some delete url">Delete Comment</a>
  <% end %>
</li>

And that will only render the link to delete a particular comment if the current user is the comment's author. No problem.

However, now that I'm rendering comments on the client side using JavaScript templates (which are cached afaik), I don't have access to current_user . I can't tell if the user currently using my app is the author of the comment or not so I can't control what he gets to see.

Sure, he won't be able to delete the comment either way because I authorize on the server as well but I'd rather not show hin the link in the first place.

How can I accomplish this?

I'd love some links to resources on this topic as well as answers because I can't seem to find any, even though it seems to me like this is a topic that should have been covered in countless blogs.

I prefer using following approach.

First, in your layout, generated on server-side, pass current user's data that you'll need on client side:

<script type="text/javascript">
    window.currentUser = {
        id : "<%=current_user.id%>"
    }
</script>

It will be accessible in your EJS templates. Now in template, you can make the same check as on server-side:

<% if (window.currentUser && window.currnetUser.id == comment.author.id) { %>
    <a class="delete" href="some delete url">Delete Comment</a>
<% } %>

This is sometimes called Client Side Personalization. It involves using css classes to hide and show certainly elements based on a value that javascript gets from a cookie or an ajax request.

I prefer setting user state, name, and other key data in a cookie that is set in a rack middleware that wraps the caching layer. This way, the logic for user session can be isolated from cached data. Then I use javascript to read this cookie and alter the page as needed. In the case of the comments example that you gave, I would render each comment with a digest of its ID (or just the id, if you aren't concerned about the security implications) in a data attribute, like so:

<div class="comment_203948">...</div>

and store the ids of a user's comments in the aforementioned cookie. Then javascript reads the cookie and finds all comments with those ids, and shows the 'delete' link for them.

A common problem with this approach involves what happens when the cookie overflows, as would happen in this example with a prolific commenter. Another approach is to use ajax to fetch the user's relevant JSON data, then to cache that in local storage. I like to combine that with keeping a version of the user's JSON data in a cookie that can be updated on the server-side with after_save callbacks and other cache-expiry strategies. Javascript then simply compares the state of the user's JSON found in local storage with the version in the cookie, and refreshes this JSON via an ajax request when it's stale.

For some further tips on Client Side Personalization, see this post under "client side cache personalization": http://www.tumblr.com/tagged/caching

and this one: http://pivotallabs.com/users/nick/blog/articles/297-making-rails-wicked-fast-pagecaching-highly-personalized-web-pages

Ryan Bates describes a common practice for that case, let me explain. It helps with Dynamic Page Caching , when you use page caching, but need to get something from the serverside and handle it.

Is about to render page without "Delete" link, then get a request to check if user session or not and assign the result to a variable.

One of implementation, a little bit deeper:

   # controller
   class UserSessionController < ActionController::Base
     skip_before_filter :require_user, :only => [:new, :create, :user_sign_in]

     def user_sign_in
       if current_user
         render :text => 'success'
       else
         render :text => 'false', :status => 403
       end
     end
   end


   class CommentsController < ApplicationController
     def has_right
       current_user == @comment.author
     end
   end


   # view
   <% javascript_tag do %>
    var a = $.getJSON('/user_session/user_sign_in', function(data){
        console.log(data)
    });

   <% end %>

Then handle the result and hide/show comments divs.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM