-
Website
None -
Original page
http://e168f07.7fff.com/2007/12/22/implementing-a-great-final-project/ -
Subscribe
All Comments -
Community
-
Top Commenters
-
steveharris
11 comments · 2 points
-
lleahy
1 comment · 1 points
-
Daniel Ha
2 comments · 435 points
-
amynewell
1 comment · 2 points
-
Mhoram
1 comment · 1 points
-
-
Popular Threads
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...
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...
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!
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
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
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.
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.