Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rails 3.1 How do I create an API route for "me" that points to the user resource

I have a set of API routes in rails as follows

namespace "api" do
   namespace "v1" do
     resources :users do
       resources :posts
       resources :likes
       ...
     end
   end
end

So far, so good. I can GET /api/v1/users/fred_flintstone and retrieve all of the information for that user.

What I would like to do now is add the concept of "me" (ala facebook) such that if the user is authenticated (fred_flintstone), I can also do the following

GET /api/v1/me

GET /api/v1/me/posts

...

I require both sets of routes. So I want to achieve the same results either using GET /api/v1/me/posts OR GET /api/v1/users/fred_flintstone/posts.

I've been through the route tutorial and have googled so a pointer would be as much appreciated as a direct answer.

EDIT:

What I've done that has worked is pretty hacky. I've created a second set of entries in the routes table using a scope:

scope "/api/v1/me", :defaults => {:format => 'json'}, :as => 'me' do
  resources :posts, :controller => 'api/v1/users/posts'
  resources :likes, :controller => 'api/v1/users/likes'
  ...
end

And then I added a set_user method that tests for the presence of params[:user_id]. I'm really looking for a way to DRY this up.

like image 867
Kris Robison Avatar asked Apr 11 '12 22:04

Kris Robison


People also ask

What is an API route?

API stands for Application Programming Interface, meaning it's how to communicate with the system you are creating. A route within an API is a specific path to take to get specific information or data out of.

How many types of routes are there in Rails?

Rails RESTful Design which creates seven routes all mapping to the user controller. Rails also allows you to define multiple resources in one line.

How do routes work in Rails?

Rails routing is a two-way piece of machinery – rather as if you could turn trees into paper, and then turn paper back into trees. Specifically, it both connects incoming HTTP requests to the code in your application's controllers, and helps you generate URLs without having to hard-code them as strings.


1 Answers

What about leaving the routes the way they are in your post, and just solving this inside the controller?

Heres a before_filter that you could apply to all of the routes you have which pull a User from a :user_id.

# Set the @user variable from the current url; 
# Either by looking up params[:user_id] or
# by assigning current_user if params[:user_id] = 'me'
def user_from_user_id
  if params[:user_id] == 'me' && current_user
    @user = current_user
  else
    @user = User.find_by_user_id params[:user_id]
  end

  raise ActiveRecord::RecordNotFound unless @user
end

Then in your controller functions you can just use the @user variable without having to worry about whether the user passed a user_id, or me.

Hope that helps! :)

EDIT:

Lemme take another shot, given your comments.

How about a function that lists all the resources you wish to access via both the standard routes and the /me route. Then you can just use the function in both the namespaces you require.

routes.rb

# Resources for users, and for "/me/resource"
def user_resources
  resources :posts
  resources :likes
  ...
end

namespace 'api' do
   namespace 'v1' do
     resources :users do
       user_resources
     end
   end
end

scope '/api/v1/:user_id', :constraints => { :user_id => 'me' },
                          :defaults => {:format => 'json'}, :as => 'me' do
  user_resources
end

# We're still missing the plain "/me" route, for getting
# and updating, so hand code those in
match '/api/v1/:id' => 'users#show', :via => :get,
                                     :constraints => { :id => 'me' }                
match '/api/v1/:id' => 'users#update', :via => :put,
                                       :constraints => { :id => 'me' }
like image 67
goggin13 Avatar answered Sep 26 '22 21:09

goggin13