Skip to main content

Mobile Rails API with Devise

For the past two weeks I have been working on building out an API for one of our existing Rails apps for use by mobile devices. I started with Android since there were less barriers to entry there (no specialty development hardware needed) as well as perceiving that Java might be more beneficial for my career in the long-run than the Apple-centric Objective-C language. It took me quite awhile to wrap my head around what exactly I needed to accomplish to get this happen at the beginning; many of the tutorials and how-to's out there are outdated and not quite what I wanted, but I think I figured out an effective, secure and easy way to help get you started should you need to accomplish something similar.
Before I do anything with the mobile device, we need to build out an API that can be communicated with on the server side of things. In rails, this is remarkably easy. My goal was to allow a user to login remotely, then be able to send either email or text messages to the members of their organization from their phone. For user authentication, our Rails app, like many out there, used Devise to handle user authentication already, so to keep things simple, I decided to take advantage of some of the features Devise has built-in for helping with login. First off, we'll need to edit some routes and add a controller for our API actions.

routes.rb
namespace :api do
  namespace :v1 do
    devise_scope :user do
      post "/sign_in", :to => 'session#create'
      delete "/sign_out", :to => 'session#destroy'
    end
  end
That is the code I ended up adding to my routes.rb file. After some research, I decided to follow a convention advocated by many modern Rails developers and use namespace's to both separate my API from existing application routes and to also version my API in case, down the road, the API is changed and might break features existing users rely upon. Even with a simple use-case like the one here, I'd still advocate doing the same thing since it is a simple, easy option with few downsides should change be necessary in the future. Because of the way namespacing works in Rails 3, this will automatically link URLs like www.example-site.com/api/v1/sign_in and www.example-site.com/api/v1/sign_out that we can use on the mobile side of things to access the controllers we are going to make next.
We need to make the controllers for logging in and logging out. I wanted to take advantage of existing Devise functionality, so I wanted my mobile app to be able to login by creating a Devise session and logout by destroying it.
First off, I want to create an API controller that my other controllers will inherit from:
rails generate controller Api/V1/Api
In this controller, we only really need one extra line of code:
class Api::V1::ApiController < ApplicationController
  respond_to :json
end
This will ensure that the rest of our controllers respond to the JSON parameters we will be sending from our mobile app.
Make another controller, this time to handle the sessions:
rails generate controller Api/V1/Sessions create destroy
In the new file created, you can replace the existing boilerplate code with the following skeleton:
module Api
  module V1
    class SessionController < Api::V1::ApiController
      def create
      end

      def destroy
      end 
    end
  end
end
Now I used a few sites to help me figure out what I needed to do here, you can check them out at:
http://jessewolgamott.com/blog/2012/01/19/the-one-with-a-json-api-login-using-devise/
https://gist.github.com/jwo/1255275
Now, how we're going to need to figure out how to handle authentication securely and make sure that only authenticated users can access other aspects of the API. We're going to take advantage of Devise's wonderful token_authenticatable module that will make creating and using an authentication token simple and easy. If you already have Devise installed and setup for your Rails app, you'll need to go back and add token_authenticatable support into the app.

Comments

Popular Posts

How to pass hash in Postman

nginx: unrecognized service

Bootstrap Select Picker append add new item if search not exist

Reading Excel Sheets using "Roo" gem in ruby on rails

Add CORS to Nginx on AWS Elastic Beanstalk

Enable gzip compression on Elastic Beanstalk with nginx

Can't connect to local MySQL server through socket '/var/run/mysqld/mysqld.sock'

Get video duration by URL in Ruby on Rails

site-enables nginx setting in ruby in rails