Building an Angular Application on a Rails Backend: Part 1

Github Repo
Video Demo

This is the first of a three part series about the insights I gained while building my first AngularJS application using Ruby on Rails in the backend. This particular post is about the Rails back end and retrieving JSON data. There are almost certainly better ways to do some of these things, but this is how I did it and what I learned.


Building a Ruby on Rails application often involves some “magic”, as it’s often called. One piece of this magic is involved with how a controller action automatically knows to render a view that shares the correct folder and name of that action. For example, if I had a ProductsController with an index action, Rails would look for a file called index.html.erb located in a folder named product nested within the app/views directory. This works great for a standard application, but if I wanted to add AJAX functionality I would need to find a different method since parsing an html document and sussing out all the needed parts would quickly become overwhelming.

One way to deal with hooking up a front end JavaScript framework to the Rails back end, is to have the controller actions return JSON data and then use JavaScript to parse that data. Using this method can make it easier to add AJAX functionality without triggering a complete page reload, which makes for a much smoother user experience.

Let’s now go back to that ProductsController I mentioned earlier. A very simple version of that controller could look like this:

  class ProductsController < ApplicationController
    def index
      @products = Product.all
    end

    def show
      @product = Product.find(params[:id])
    end

    def new
      @product = Product.new
    end

    def create
      @product = Product.new(product_params)

      if @product.save
        flash[:success] = "Product created!"
        redirect_to @product
      else
        render 'new'
      end
    end

    def edit
      @product = Product.find(params[:id])
    end

    def update
      @product = Product.find(params[:id])

      if @product.update_attributes(car_params)
        redirect_to @product
      else
        render 'edit'
      end
    end

    def destroy
      Product.find(params[:id]).destroy
      redirect_to products_path
    end

    private
      def product_params
        params.require(:product).permit(:name, :item_price, :sell_price, :quantity)
      end
  end

There’s nothing too out of the ordinary in there, sure it could be more complex but I’m trying to keep this relatively basic. Each controller action will return a string of HTML which the browser will then render on the page for the user to view.

To upgrade this application into a single page app (SPA), I have to change the output of each of those controller actions to return JSON. The easiest and quickest way to change the output is using the powerful render method provided via the ActionController::Base class. The render method can be used to display a variety of files and file types, such as simple templates, HTML, plain text, XML, and even the coveted JSON.

For example, looking at the Products#index action, it’s very simple to change the output like below:

  def index
    @products = Product.all

    render json: @products
  end

This works great for what we need to setup a SPA, but in order to make the application extremely flexible, it could be valuable to have the controller return multiple file types. Rails has another method nested inside ActionController called respond_to which provides this functionality. This method will examine the server request and depending on the file type of that request, it will provide a return value of similar filetype. In the example below, the browser would be provided a response in kind with the request. So if it was /products.json, the response would be JSON; if /products.xml, the response XML.

  def index
    @products = Products.all

    respond_to do |format|
      format.html { render :index }
      format.json { render json: @products }
      format.xml { render xml: @products }
    end
  end

Once again, this provides the functionality to create a SPA already, but while completing my project, I found of another way of metaprogramming the response like below. This might not be as readable as the above format, it is certainly much more maintanable code since you only have to add the format type as an input to the .any block.

  def index
    @products = Products.all

    respond_to do |format|
      format.html { render :index }
      format.any(:xml, :json, :text) { render request.format.to_sym => @products }
    end
  end

I recommend checking out this respond_to documentation to learn even more.

In the next segment of this series, I’m going to show how to setup AngularJS on the front end of a Rails application and get it up and running.

Added on August 25, 2016