DISQUS

CSCI E-168, Fall 2007: Implementing a great final project

  • anne002 · 2 years ago
    For those of us who had trouble with assignment 5, will you post the code you wrote?

    Do you have an upgraded version of Child care coop, so we can use it over the web the way we used the previous version as guidance for what some of the features might look like -- for example for email, authentication...
  • jgn · 2 years ago
    Owing to a medical issue, there is a student who will hand in this weekend. Once that is in, I will distribute a solution.
  • bchin · 2 years ago
    For the implementation of UUID are we supposed to write code to generate a UUID or can we use external libraries?
  • jgn · 2 years ago
    It is up to you. All you are trying to do is get a good quasi-random but unique value that can serve as an alternate key. A lame approach is to use a random number with a lot of bits. But you can do better; a decent GUID can be generated in about a line of Ruby. You may find it easier to write one yourself from scratch, or you may find it easier to use a library -- read on. Whatever you do, make sure to address your choice and strategy in your writeup. Just FYI, knowing how to generate a decent GUID -- or the libraries that would help in whatever language you're using -- is a very useful thing to have around. There are many times when you want to give a file a name you know to be unique: Having part of the filename be based on a GUID is one way to do it. And there are many other uses.

    A GUID (or UUID) is a globally-unique identifier. The "classic" GUID is built out of the MAC address (the hardware address of your network adapter) + a time value + a counter. You concatenate all of those things, and then figure out a way to represent the value at a standard length and with a standard character set. Just for example, you could hash that value using Digest:: SHA1.digest (there should be a discussion of this in the Pickaxe), and then you would do something like Base64-encode it (this also should be in the Pickaxe).

    For the MAC address + time + counter core value, you can also use the UUID class here:

    http://trac.labnotes.org/cgi-bin/trac.cgi/wiki/...

    (Notice how in the code the returned value is a little gross: This is why you might want to hash and base64 it.)

    If you decide to write your own, a somewhat acceptable value instead of the MAC address is to use the IP address of the computer, though in production the computer can be on a subnet and not have an especially good value. But in reality, it isn't totally necessary to have a "real" globally-unique value: It can be enough that it is unique in your own product.

    Here's some more information for the general idea:

    http://en.wikipedia.org/wiki/Universally_Unique...
  • bchin · 2 years ago
    Hi,

    I'm trying to figure out how to implement REST with the CCC project. Since there's a filter on all the routes except for the login page that checks for authentication, does this mean that you need to be authenticated to access the REST interfaces that you access? I'm unclear on how that works. For example, if I were to provide an interface to access my schedule, what would be the strategy for authentication? Or should the filter be changed to check for the type of format that is requested?

    Thanks!
  • jgn · 2 years ago
    There are a number of ways to do this.

    The key is that in all cases, you do not use the web-based (form-style) authentication. Why? Because you don't want to use the session to track the "current" user. As you will recall, maintaining state in REST is a no-no.

    Here are two strategies, plus one I wish I could offer you, but it's only Rails 2.0.0+:

    *ONE*

    (1) Omit the REST paths from authentication

    (2) Expose all data via REST

    But note: This is an app where not much is actually very public. Maybe the list of locations. You could implement nested resources like:

    /users/1/playdates

    but it is cool to provide any random user with a list of John's playdates? Having said that, this is the way to start. Get this working, then think about option two, into which you would refactor your working code.

    *TWO*

    (1) Omit the REST paths from authentication

    (2) Add a column to the users table with is a GUID for that user. Now allow requests like this:

    /users/GUID/playdates

    So it might be:

    /users/OEeaw-64kD4p5XBcfjn_-F1HPPg/playdates

    This is "security by obscurity." A user who wants to get his data via REST would need to know his GUID.

    *THREE*

    Ideally, you would use authentication during the HTTP request. E.g., with HTTP "basic" authentication.

    Unfortunately this isn't supported out-of-the-box with Rails 1.2.3.

    This is the idea:

    http://railscasts.com/episodes/82
  • steveharris · 1 year ago
    I'm deploying the RESTful acts_as_authenticated, which (if I'm understanding what I'm seeing) uses a cookie.

    I'm following Alameda's example (chapter 6) -- in his controllers, he restricts every request to only the records "owned" by the current_user, e.g.:

    def index
    exercises = current_user.exercises.find(:all)
    ...
    end

    But this appears to violate the REST statelessness principle.

    Sigh. Back to the drawing board...

    - Steve
  • jgn · 1 year ago
    Steve, When you use acts_as_authenticated, note that it is "in play" if someone logs in via a browser. So then the use of the session is legit (and saving "state").

    But if they come in requesting XML, then you should probably not check the session. This implies, then, that for REST requests, you should not look at the session.
  • Philipp · 1 year ago
    "If I am not already logged in, I should be given an opportunity to log in." sort of implies that once the user logs in they are magically sent to the /invitations/invite/### URL. The existing code does does, in a very primitive way, give "an opportunity to log in", but then bumps you to the main page, rather than taking you where you had initially asked to go. May we assume that once they log in they can click on the link in the email again and we take them to the correct page, or are we expected to implement some kind of more-intelligent login system as well?
  • jgn · 1 year ago
    Glad you asked. I've been waiting for someone to ask about this.

    The "intelligent" strategy goes like this:

    -- At some point you have code that sees that the user has made a request, but is not logged in. In CCC, this is done in ApplicationController#authorize

    -- So what you want to do is: In the code that detects that a user is not logged in, you need to save the incoming request somewhere. For instance,

    session[:wanted_path] = request.env['REQUEST_URI']

    (I think that's the right item in the request.)

    See http://api.rubyonrails.org/classes/ActionContro... under "Requests" for information about this.

    This happens before you redirect to the login action.

    -- Then, after a successful login, you want something like the following:

    if session[:wanted_path]
    p = session[:wanted_path]
    session[:wanted_path] = nil
    redirect_to p
    return
    end

    The bit where we are redirect to a path or URL is something you've seen before: We do it in LinkWizz to handle bookmarking via the toolbar. There's a line like this:

    redirect_to @link.url

    which is a very similar idea, except that it's an absolute URL instead of one that is understand as local to the server.