2: Creating the base rails backend

In this portion of the Rails4 and AngularJS tutorial we build the base of the rails backend.  We’ll come back later and add Devise and CanCan to it, for now we’re just focusing on having an application that runs and serves json, at the end of this segment you should end up with a Rails server that is providing clubs.json and teams.json, ready to have the Angular frontend added.

If you’re interested in the rest of this tutorial, you can visit the index page, or you can hit the tutorials menu above and look at the rails 4 tutorial category.  If you haven’t yet installed Rails 4 you may want to look at the previous page on installation, and if you’re fine with the Rails portion, you may want to move onto the next page that starts the AngularJS install.  Finally, the code for the position at the end of this section of the tutorial can be found on github:PaulL:tutorial_1_and_2.

In your browser, the aim of this section of the tutorial is to get something like the screenshot below:

The base application has two entities, loosely based around a sports league.  It has a set of clubs, with each club having multiple teams.  In later sections of the tutorial we’ll set it up so that only some users can edit some clubs, but for now we’re completely ignoring the security.

If you didn’t already do so in the previous page, create a new rails application:

rails new league-tutorial-rails4

Run the installer to make sure everything is installed:

bundle install

Initialise your git project if you want to use git (I won’t note where you should be committing along the way, but it’s good practice to do regular commits to allow you to get back to what you had before):

git init --shared=group

Start off by creating the club entity.  A club is very simple – it has a name, a contact_officer, and a date_created:

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

Migrate the database:

rake db:migrate

We next want to change our controller to:

  • Explicitly reject html, and accept only json
  • Drop all the html options in the responses

Edit the rails controller app/controllers/clubs_controller.rb as follows:

class ClubsController < ApplicationController
  before_filter :intercept_html_requests
  layout false
  respond_to :json
  before_action :set_club, only: [:show, :edit, :update, :destroy]

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

  # GET /clubs/1
  # GET /clubs/1.json
  def show
    render json: @club
  end

  # POST /clubs
  # POST /clubs.json
  def create
    @club = Club.new(club_params)

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

  # PATCH/PUT /clubs/1
  # PATCH/PUT /clubs/1.json
  def update
    if @club.update(club_params)
      head :no_content
    else
      render json: @club.errors, status: :unprocessable_entity
    end
  end

  # DELETE /clubs/1
  # DELETE /clubs/1.json
  def destroy
    @club.destroy

    head :no_content
  end

  private
    # Use callbacks to share common setup or constraints between actions.
    def set_club
      @club = Club.find(params[:id])
    end

    # Never trust parameters from the scary internet, only allow the white list through.
    def club_params
      params.require(:club).permit(:name, :contact_officer, :date_created)
    end

  # if someone asks for html, redirect them to the home page, we only serve json
  def intercept_html_requests
    redirect_to('/') if request.format == Mime::HTML
  end
end

We then update the routes to match:

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

You can delete the views directory as we won’t be using them.  Add some clubs directly to the database so that we can do a bit of testing.

sqlite3 db/development.sqlite3
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');
.quit

Run the application

rails server

and see what you get when you visit http://localhost:3000/clubs.json. You should get a json response that looks like the records you put in the database.

clubs.json browser snap

Try also http://localhost:3000/clubs/1.json, which should show a single record, and try http://localhost:3000/clubs/1.html, which should redirect to the index page.

Similarly create a teams entity:

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

Set it up to return .json as before:

class TeamsController < ApplicationController
  before_filter :intercept_html_requests
  layout false
  respond_to :json
  before_action :set_team, only: [:show, :edit, :update, :destroy]

  # GET /teams
  # GET /teams.json
  def index
    @teams = Team.all
    render json: @teams
  end

  # GET /teams/1
  # GET /teams/1.json
  def show
    render json: @team
  end

  # POST /teams
  # POST /teams.json
  def create
    @team = Team.new(team_params)

    if @team.save
      render json: 'show', status: :created
    else
      render json: @team.errors, status: :unprocessable_entity
    end
  end

  # PATCH/PUT /teams/1
  # PATCH/PUT /teams/1.json
  def update
    if @team.update(team_params)
      head :no_content
    else
      render json: @team.errors, status: :unprocessable_entity
    end
  end

  # DELETE /teams/1
  # DELETE /teams/1.json
  def destroy
    @team.destroy

    head :no_content
  end

  private
    # Use callbacks to share common setup or constraints between actions.
    def set_team
      @team = Team.find(params[:id])
    end

    # Never trust parameters from the scary internet, only allow the white list through.
    def team_params
      params.require(:team).permit(:club_id, :name, :captain, :date_created)
    end
end

You’ll notice the intercept_html_requests method isn’t here, we don’t want to keep duplicating it so we’re moving it into application_controller.rb, so also take out of the clubs_controller.rb.  The application_controller should look like:

class ApplicationController < ActionController::Base
  # Prevent CSRF attacks by raising an exception.
  # For APIs, you may want to use :null_session instead.
  protect_from_forgery with: :exception

  # if someone asks for html, redirect them to the home page, we only serve json
  def intercept_html_requests
    redirect_to('/') if request.format == Mime::HTML
  end
end

Update the routes to add teams:

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

Migrate the database, and put some records in:

rake db:migrate

sqlite3 db/development.sqlite3
insert into teams values (1, 1, 'First team', 'C.F.Captain', '2012-01-01', '2012-02-02', '2012-03-03');
insert into teams values (2, 1, 'Second team', 'A.N.Captain', '2012-01-01', '2012-02-02', '2012-03-03');
.quit

Check that you can see teams by visiting http://localhost:3000/teams.json.

You’ll notice that we didn’t make teams a nested route of clubs – we’re assuming that teams can either be inside a club, or can exist outside a club.  So we’re going to leave the club_id as optional on the team, and create the relationship within our angular app later.

This post will be updated for CSRF and JSONP vulnerabilities once we have some AngularJS working against it and can verify whether that all works or not.

The code for the position at the end of this section of the tutorial can be found on github:PaulL:tutorial_1_and_2, the next step in the tutorial is getting ourselves some angularjs.

Advertisements

3 thoughts on “2: Creating the base rails backend

  1. Pingback: AngularJS and Rails 4 CRUD application using ng-boilerplate and twitter bootstrap 3: Tutorial Index | technpol

  2. Pingback: Installing Rails 4 without breaking Rails 3 | technpol

  3. Pingback: 9: Adding the teams entity, and links from clubs to team | technpol

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