Rails 3: routing to customer areas - ruby-on-rails-3

I'm a Rails 3 beginner, but have experiences with other MVC web frameworks and need a starting hint about how to setup my routing in Rails. The application should allow users to register and after that the users data should be available at URLs like:
http://domainname/username/xyz
The common and user independent part should be available at
http://domainname/abc
To distinguis between both routes, I would force usernames to have at least 6 characters and all "abc"-routes will have 5 or less. Until this point I would be manage the routing by myself, but for the "xyz" part of the user area I would like to use the existing REST full features of rails. Any hint how to do that?

Have you already read http://edgeguides.rubyonrails.org/routing.html?
It's really a good resource for this sort of question. I believe some of the scheme you describe falls into the "Non-Resourceful" routing category.

Related

Consuming a REST API endpoint from a resource ID

Lets consider the following flow to a RESTfull API:
API root
|
v
user list
|
v
user details
|
v
user messages
Suppose I have a client to consume the API, and I want to retrieve messages from a user with ID 42.
From what I've been studying, my client is not supposed to know how to "build" urls, and it should follow the links given by the API.
How should I do to retrieve messages for the user with ID 42?
The only way I can think is "walk" the whole API from it's root to user messages, which doesn't look very pretty or efficient to me.
Eg:
1 - GET / and get the link to the list of users
2 - GET /user/?id=42 and get the link to details of the user with the ID 42
3 - GET /user/42/ and get the link to user 42 list of messages
4 - GET /user/42/messages/ and finally get the user messages
Did I get something wrong? Is this the right way according to Roy's Fielding paper?
Or is it ok to just assume the messages url is "/user/{id}/messages/" and make the request directly?
Use URL templates in your API root. Let the client consume the API root at runtime. It should look for a URL template named something like "user-messages" with the value of "/user/{userid}/messages/". Then let the client substitute "42" for "{userid}" in the template and do a GET on the resulting URL. You can add as many of these URL templates you want for all of the required, often used, use cases.
The difference between this solution and a "classic" web API is the late binding of URLs: the client reads the API root with its templates at runtime - as opposed to compiling the client with the knowledge of the URL templates.
Take a look at the HAL media type for some information about URL templates: http://stateless.co/hal_specification.html
I wrote this piece here some time ago to explain the benefits of hypermedia: http://soabits.blogspot.dk/2013/12/selling-benefits-of-hypermedia.html
I believe what your real concern is should you go about implementing HATEOAS or not. Now as it's an integral part of REST specifications, it is recommended that each entity should have a link to it's child entity that it encompasses. In your case, API ROOT should show list of users with each "user" having a link (/root/users/{id}) to corresponding user's details. And each User details entity will contain a link to the list of "messages" (/root/users/{id}/messages) which, finally, inturn encompass the link to the actual message detail as well (/root/users/{id}/messages/{messageId}). This concept is extremely useful (and thus a part of the specifications) because the client doesn't need to know the url to where your entity is exposed. For example, if your users were on http://users.abc.com/rest/users/{id} but your messages were on http://messages.abc.com/rest/{userId}/messages/{messageId}, the user entity that encompasses the list of "messages" will already have link embedded to point to the right resource on a different server.
Now that being said, I haven't actually seen many REST implementations out there (I must admit I do not have TOO MUCH of an experience, but enough to give an opinion) where HATEOAS is being used widespread. In most cases the resources are almost always on the same server (environment) and the paths to resources are almost always relative to the root url.Thus, it doesn't make sense for the clients to parse out the embedded links from the object when they can generate one by themselves, especially when the client would like to provide access to a resource directly (View the message directly without getting the user entity provided you already know what the messageId is).
In the end, it all depends on how close do you want your REST implementations to that of specifications and what kind of clients are you going to have. My 2 cents would be: if you have time, implement REST with HATEOAS and feel proud about it :). There are libraries out there that will make this implementation (HATEOAS) somewhat transparent to you REST implementation (I believe spring has one, although not very mature. You can look at it here). If you are like me and don't have much time to go that route, I think you can continue with a normal REST implementation without HATEOAS and your clients will still be OK with it (or so I hope!)
Hope this helps!
I found this article about hacking urls: Avoid hackable URLs.
There is a very interesting discussion about the topic of this question in the comments section.

How to implement HATEOAS in Rails

I've started with ActiveResource, but quickly hit the wall. Could not get ActiveResource to work when overriding to_json and to_xml on the underlying model. Plus, could not make resource representation inject links into the generated xml document. Oh btw, I'm using Rails 3.2.1.
I did a bit of research and found out about its gem. Tried it, for some reason didn't work for me. So my question is:
If I have one resource (say books) hosted in one web site (something like http://books.org), and another resource (say students, http://students.org), hosted in another web site, how can I get books to represent themselves to a student in their full HATEOS glory?
I was able to get the book resource to represent itself to the asking student as an XML document. I did that by using vanilla Rails ActiveResource in the students site. I've created Books resource that inherits from ActiveResource::Base. Then I specified the self.site and self.element_name, after which I was able to perform some rudimentary ActiveRecord-like queries against the remote books site. The only thing that worked for me was Book.all and Book.find(1). Even that was not satisfactory because the representation contained all database columns, and I wanted to at least remove some of those, which turned out not to be possible.
Now that I've abandoned that approach, I am wondering if there is a working example in Rails where it is possible to build a more sophisticated representation of a resource (i.e. books) that will contain links that will drive the application state transfer? I find it simply unbelievable that such a simple requirement seems so devilishly difficult to implement in Rails. All I'm trying to do is create a representation of a resource that will include some links which will guide the consumer on its discovery of what that resource is capable of. I'm mostly interested in implementing the workflow, which is a layered, peeling-the-onion type of conversational process of discovery.
In Rails, you'd need to change the way the serialization of your object happens if you're looking to do this in JSON. (You need to override the way Rails gives back representations of resources.) The most common gem for doing that would be: https://github.com/rails-api/active_model_serializers
If you don't want to use AMS or want to return HTML, consider following this presenter pattern: http://blog.steveklabnik.com/posts/2012-01-06-implementing-hateoas-with-presenters

Strategies for dealing with split application

To deal with recent growth our application has been split across two sets of separate infrastructure. Approximately half of our customers are on set 1 and the other half are on set 2.
Both sets have different urls (api1.ourdomain.com and api2.ourdomain.com).
Problem is clients accidentally putt the wrong url and then wonder why they get error messages.
Other then user education any other strategies for dealing with this mess?
Is it possible to redirect requests to the correct endpoint?
Thanks.
I don't think your question is detailed enough to provide meaningful feedback. There are obviously several factors that could easily contribute to a recommendation.
Does your application make use of user profiles (or a similar construct)? If so you might consider associating a primary URI for each user in their profile and include logic in your application to interrogate the profile for each request and redirect if a user goes to the wrong URI.
Is this an authorization issue? If so you might consider including some basic authorization routing that provides a custom 403 page with the proper URL.
If you could provide additional detail I think we could be more helpful.

Rails 3 CMS + blog wanted to fit existing site. Unobtrusive and Lightweight

I'd like to add a CMS and blog to a web app. One that won't get in the way. There's not a lot of content, but enough that we want non-devs to be able to revise pages and probably add and remove them too.
We have a substantial app that can't be touched by the CMS, not a site that we're migrating.
How have you dealt with this situation?
Would you advise:
Running two apps (a content app and the 'app' app)
Plugging in a light weight CMS
Rolling our own using gems/plugins for WYSIWYG
Details
We'll be adding a bug ticketing and support system later too. Probably built into the app.
We'd like the users of the app to be able to comment on pages and blog posts, file tickets, etc. all from their main account, so it seems to make sense to build it into our app, rather than as an extra app. Love to hear war stories on this.
Should be:
Unobtrusive (Shouldn't interfere with the existing app)
Must not mess with Devise, DeclarativeAuthorization, or Omniauth. We've got extensive user accounts, permissions, authentication mechanisms and groups setup. These must stay.
Lightweight (prefer something dev friendly than feature loaded)
Desired Features:
Basic WYSIWYG for content editors
Lets us handle accounts (with Devise)
and maybe even permissions (with DeclarativeAuthorization)
I've read this similar question, but the author seems willing to have something a bit more intrusive.
Simple Rails 3 CMS Gem/Plugin?
Options Found
Refinery seems to have a lot of features, but at a cursory look it needs a lot of control over what's going on: http://refinerycms.com/guides/attaching-refinery-cms-to-an-existing-rails-application It says it's modular, but it seems like there's a big chunk of non optional stuff in there.
Radiant seems a bit monolithic as well
http://groups.google.com/group/radiantcms/browse_thread/thread/b691cf9ab644a8b2
ComfortableMexicanSofa seems a bit closer to what I want: https://github.com/twg/comfortable-mexican-sofa
Adva-Cms has the right philosophy but appears to be dead. Adva-Cms2 isn't ready
http://adva-cms.org/
Governor seems good, but maybe a bit too young and lean
https://github.com/carpeliam/governor
Conclusion
So far rolling our own, or using ComfortableMexicanSofa seems like the bet, but I'd like your thoughts before I spend a few days messing around with it.
I am now rolling my own blog app and I am kind of newbie to Rails 3. Even like that, in 1 week i have a blog with tags, comments, authentication with omniauth, etc.. my advise is: roll your own. I was having the same doubt and looking for pre-made solutions and I decided to start it from zero and just look for plugins for anything i need.
It goes pretty fast if you know already some rails programming and you use the right plugins. This is what i used:
Omniauth to let users be able to autenticate with facebook, twitter etc.. and leave you comments.
rails_admin: it allows you to manage your blog by going to yourapp.com/admin. It uses devise to create an Admin user (you can specify a diferent model name than user to not to mix it with the users from omniauth or from your other app) and if you have the right models and associations between them you can from there create your posts, assign them tags or categories and also delete comments etc.. its all done in an easy way. For the Text Area that you use to introduce the content of your posts you can associate it with the ckeditor just by adding to the rails_admin initializer something like:
config.model Post do
edit do
field :body, :text do
ckeditor true
end
end
end
And with the ckeditor you can introduce pictures, attach videos, format text, and so on.
Use kaminari for pagination, or you can use will_paginate if you are more used to that.
Using the blueprint framework for styling with css you will save time and have a more standar styling.
Use few jquery lines to insert/delete comments graciously.
And that's all I can remember now. And if it shouldn't interfere with the main app, i would just assign a subdomain for it. So if you go to blog.myapp.com you access to the blog and if you go to myapp.com you access to the app. And you want users from the app to interact with the blog so you should use just one app and have this 2 subdomains pointing at differents parts of the same a app.. take a look at: rails 3 - one app, multiple domains, how implement a different 'root' route for one of the domains?
That's all i can think now! let me know if i can help you in anything else.
rails_admin: it allows you to manage your blog by going to yourapp.com/admin. It uses devise to create an Admin user (you can specify a diferent model name than user to not to mix it with the users from omniauth or from your other app) and if you have the right models and associations between them you can from there create your posts, assign them tags or categories and also delete comments etc.. its all done in an easy way. For the Text Area that you use to introduce the content of your posts you can associate it with the ckeditor just by adding to the rails_admin initializer something like:
config.model Post do
edit do
field :body, :text do
ckeditor true
end
end
end

Suggestions on addressing REST resources for API

I'm a new REST convert and I'm trying to design my first RESTful (hopefully) api and here is my question about addressing resources
Some notes first:
The data described here are 3d render
jobs
A user (graphics company) has multiple projects.
A project has multiple render jobs.
A render job has multiple frames.
There is a hierarchy enforced in the data (1 render job
belongs to one project, to one user)
How's this for naming my resourses...?
https:/api.myrenderjobsite.com/
/users/graphicscompany/projects
/users/graphicscompany/projects/112233
/users/graphicscompany/projects/112233/renders/
/users/graphicscompany/projects/112233/renders/889900
/users/graphicscompany/projects/112233/renders/889900/frames/0004
OR a shortened address for renders?
/users/graphicscompany/renders/889900
/users/graphicscompany/renders/889900/frames/0004
OR should I shorten (even more) the address if possible, omitting the user when not needed...?
/projects/112233/
/renders/889900/
/renders/889900/frames/0004
THANK YOU!
Instead of thinking about your api in terms of URLs, try thinking of it more like pages and links
between those pages.
Consider the following:
Will it be reasonable to create a resource for users? Do you have 10, 20 or 50 users? Or do you have 10,000 users? If it is the latter then obviously creating a single resource that represents all users is probably not going too work to well when you do a GET on it.
Is the list of Users a reasonable root url? i.e. The entry point into your service. Should the list of projects that belong to a GraphicsCompany be a separate resource, or should it just be embedded into the Graphics Company resource? You can ask the same question of each of the 1-to-many relationships that exist. Even if you do decide to merge the list of projects into the GraphicsCompany resource, you may still want a distinct resource to exist simple for the purpose of being able to POST to it in order to create a new project for that company.
Using this approach you should be able get a good idea of most of the resources in your API and how they are connected without having to worry about what your URLs look like. In fact if you do the design right, then any client application you right will not need to know anything about the URLs that you create. The only part of the system that cares what the URL looks like is your server, so that it can dispatch the request to the right controller.
The other significant question you need to ask yourself is what media type are you going to use for these resources. How many different clients will need to access these resources? Are you writing the clients, or is someone else? Should you attempt to reuse an existing standard like XHTML and classes/microformats? Could you squeeze most of the information into Atom? Maybe Atom with some extra namespaces like GDATA does it? Or is this only going to be used internally so you can just create your own media types, like application/vnd.YourCompany.Project+xml, application/vnd.YourCompany.Render+xml, etc.
There are many things to think about when designing a REST api, don't get hung up on what your URLs look like and you should really try to avoid doing "design by URL".
Presuming that you authenticate to the service, I would use the 1st option, but remove the user, particularly if the user is the currently logged in user.
If user actually represents something else (like client), I would include it, but not if it simply designates the currently logged in user. Agree with StaxMan, though, don't worry too much about squeezing the paths, as readability is key in RESTful APIs.
Personally I would not try to squeeze path too much, that is, some amount of redundant information is helpful both to quickly see what resource is, and for future expansion.
Generally users won't be typing paths anyway, so verbosity is not all that bad.