Rails app for Angularjs, building the rails league application: part 1

Part 1 of a tutorial that connects AngularJS to a Rails backend. This post focuses on creating a base Rails server application that our AngularJS front end will later connect to, it assumes that you are familiar with Rails already and have all the rails dependencies installed.  The next post is Installing ng-boilerplate, and serving up via Rails.  You can also find the index of the posts in the tutorial.

There is a newer, rails 4 and newer angularJS, version of this tutorial.  It is also more complete and has a nicer UI that doesn’t use modal windows, which is probably a better choice for anyone starting fresh today.  The first page in that tutorial is here, and the index here. I’m learning AngularJS at the moment, over time I’m looking to add a richer front-end to my rails application.  I’ve found it hard to find all the information for doing this in one place, so I’m aiming to collate it in a way to allow someone else to also get to a working application, and hopefully to get over the initial AngularJS learning curve as quickly as possible. The application is very simple, I’m ignoring authentication and other complexities, and building an app that has just two entities, clubs and teams.  It’s not intended to be a real app, so the fact that a sports competition app would need more than clubs and teams is neither here nor there. This app won’t be quite like a standard rails app, since it will have no web pages, it just returns json to every request.  I’m also not being too fussy about keeping it clean – so I’m not deleting all the html pages although I probably should.  So, with that introduction, let’s quickly build the rails end of it. First, we create a new app:

  rails new league_tutorial

Update the Gemfile to have a javascript engine, since the tests don’t seem to run without:

  gem "therubyracer", ">= 0.11.0", :group => :assets, :platform => :ruby, :require => "v8"

Run the installer:

  bundle install

Create the clubs scaffold:

  rails generate scaffold club name:string contact_officer:string date_created:datetime

And migrate the database

  rake db:migrate

Then we edit app/controllers/clubs_controller.rb. The things we’re changing are:

  • delete the edit and new methods, we don’t need them as they are purely for showing a page
  • change it to always return json, never html.  I haven’t quite nailed this yet, I think if you call for html it tries to return it, so I need to explicitly return an error if anything other than json is requested

This gives a controller like the following:

class ClubsController < ApplicationController
  before_filter :intercept_html_requests
  layout false
  respond_to :json

  # GET /clubs
  # GET /clubs.json
  def index
    @clubs = Club.all
    render json: @clubs
  end

  # GET /clubs/1
  # GET /clubs/1.json
  def show
    @club = Club.find(params[:id])

    render json: @club
  end

  # POST /clubs
  # POST /clubs.json
  def create
    @club = Club.new(params[:club])

    if @club.save
      render json: @club, status: :created, location: @club
    else
      render json: @club.errors, status: :unprocessable_entity
    end
  end

  # PUT /clubs/1
  # PUT /clubs/1.json
  def update
    @club = Club.find(params[:id])

    if @club.update_attributes(params[:club])
      head :no_content
    else
      render json: @club.errors, status: :unprocessable_entity
    end
  end

  # DELETE /clubs/1
  # DELETE /clubs/1.json
  def destroy
    @club = Club.find(params[:id])
    @club.destroy

    head :no_content
  end

  private
  def intercept_html_requests
    redirect_to('/') if request.format == Mime::HTML
  end
end

We then update the routes to match:

LeagueTutorial::Application.routes.draw do
  resources :clubs, :except => [:new, :edit]
end

And we add some clubs directly to the database so that we can do a bit of testing.

 insert into clubs values (1, 'First club', 'A Person', '2012-01-01', '2012-02-02', '2012-03-03');
 insert into clubs values (2, 'Second club', 'J Jones', '2012-01-01', '2012-02-02', '2012-03-03');

Run the application, and see what you get when you visit http://<your_host>:3000/clubs.json. You should get a json response that looks like the records you put in the database. clubs.json Try also http://localhost:3000/clubs/1.json Similarly create a teams controller and set it up to return .json and update the routes to add teams:

LeagueTutorial::Application.routes.draw do
  resources :clubs, :except => [:new, :edit]
  resources :teams, :except => [:new, :edit]
end

Teams are like:

rails generate scaffold team club:references name:string captain:string date_created:datetime

Update the database:

rake db:migrate

Insert some data into the table:

insert into teams values (1, 1, 'Team 1', 'JimBob', '2012-01-01', '2012-02-02', '2012-03-03');
insert into teams values (2, 1, 'Team 2', 'Jason', '2012-01-01', '2012-02-02', '2012-03-03');

This should give you a league app that responds to teams and clubs, and gives only json. If you’re using git, now is a good time to commit.

Consider adding the following block to the application_controller.rb, in order to provide CSRF protection, more details are provided on my csrf blog post, the original idea comes from stackoverflow: rails csrf protection.  Further, the AngularJS $http documentation describes a json security vulnerability, which  could allow a cross site scripting attack.  In my json/jsonp vulnerability blog post I created the render_with_protection method to solve that issue:

class ApplicationController < ActionController::Base
  protect_from_forgery

  after_filter  :set_csrf_cookie_for_ng

  def set_csrf_cookie_for_ng
    cookies['XSRF-TOKEN'] = form_authenticity_token if protect_against_forgery?
  end

  def render_with_protection(json_content, parameters = {})
    render parameters.merge(content_type: 'application/json', text: ")]}',\n" + json_content)
  end

protected

  def verified_request?
    super || form_authenticity_token == request.headers['X_XSRF_TOKEN']
  end  
end

You’ll also need to update the render call in both controllers, below is the example for app/controllers/club_controller.rb:

class ClubsController < ApplicationController
  before_filter :intercept_html_requests
  layout false
  respond_to :json

  # GET /clubs.json
  def index
    @clubs = Club.all

    render_with_protection @clubs.to_json
  end

  # GET /clubs/1.json
  def show
    @club = Club.find(params[:id])

    render_with_protection @club.to_json
  end

  # POST /clubs.json
  def create
    @club = Club.new(params[:club])

    if @club.save
      render_with_protection @club.to_json, {status: :created, location: @club}
    else
      render_with_protection @club.errors.to_json, {status: :unprocessable_entity}
    end
  end

  # PUT /clubs/1.json
  def update
    @club = Club.find(params[:id])

    if @club.update_attributes(params[:club])
      head :no_content
    else
      render_with_protection @club.errors.to_json, {status: :unprocessable_entity}
    end
  end

  # DELETE /clubs/1.json
  def destroy
    @club = Club.find(params[:id])
    @club.destroy

    head :no_content
  end

  private
  def intercept_html_requests
    redirect_to('/') if request.format == Mime::HTML
  end
end

The code for this tutorial 1 can be found in the tutorial_1 branch on github. The next post will deal with creating an angular app to call it.

Advertisements

7 thoughts on “Rails app for Angularjs, building the rails league application: part 1

  1. Pingback: CRUD application with AngularJS, Rails, twitter-bootstrap and ng-boilerplate: part 2 | technpol

  2. Pingback: CRUD application with AngularJS, Rails, twitter-bootstrap and ng-boilerplate: part 3 CRUD | technpol

  3. Pingback: CRUD application with AngularJS, Rails, twitter-bootstrap and ng-boilerplate: part 4 grid and CRUD | technpol

  4. Pingback: CRUD application with AngularJS, Rails, twitter-bootstrap and ng-boilerplate: part 5 New and Delete | technpol

  5. Pingback: AngularJS and Rails: Tutorial Index | technpol

  6. Pingback: CRUD application with AngularJS, Rails, twitter-bootstrap and ng-boilerplate: part 6 another entity | technpol

  7. Pingback: AngularJS and Rails CRUD application using ng-boilerplate and twitter bootstrap | Gatelockservice

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s