Rails templates are powerful and give us an easy way to build a front end that integrates with our back end. However, Rails templates are also limited. They are largely static, meaning they are rendered by the controller before being sent as a response to the user. But that means a hard page reload in your browser, and that makes it more difficult to make applications that operate seamlessly like many modern websites such as Facebook or Twitter.

As seen in one of my past projects, we can use jQuery to build a single-page application that makes requests asynchronously with AJAX. However, it quickly gets complicated and hard to maintain, organize, and develop. There are many JavaScript front end frameworks that have risen over the last several years. For this project, I used Angular to build an application for uploading and sharing sketches.

Integrating Angular With Rails

Angular and Rails aren’t really designed to work together, so building an application integrating both requires some finagling. In order to get the functionality we want, we need to manage both front end and back end dependencies. Back end dependencies are easy to manage: we just use gems in our gemfile and install with bundle install. However, front end dependencies are a bit trickier. There are many Angular related gems we could use, but there aren’t gems for everything. So instead, we can use Bower.

First, we install Bower by running npm install -g bower. Then we isntall bower-rails gem through our gemfile. We specify our front end dependencies in a bower.json file. After that, we run rake bower:install, and our dependencies will be installed (the default directory being vendor/assets/bower_components). We then have to specify the dependencies in the javascript manifest file (app/assets/javascripts/application.js) to incorporate them in the asset pipeline.

Another gem we can use is angular-rails-templates to incorporate our Angular templates into the Rails asset pipeline.

You can take a look at my Bower dependencies in my bower.json file here as well as the app.js file explaining them.

Rails Back End

The back end is set up similarly to my last jQuery project, so I won’t go into it in depth. There are several models including sketches and tags. The sketch model uses Paperclip to manage file attachments. It’s easy to set up file uploads for Paperclip with a Rails form, but with Angular we will have to set up a different solution - namely ngFileUpload.

We’ll enable AJAX functionality by setting up Active Model Serializers for JSON serialization of our models through our controller actions.

Authentication is handled with Devise. Like Paperclip, it’s easy to sign in and register with Devise Rails templates, however, we’ll again have to set up something different with Angular, using angular-devise.

Angular Front End

Going over all of the front end code would be an exhaustive process, so I’ll just give a brief overview.

Since this is a single page application, we have to handle routing for pages on the front end, and for this I used ui-router. Ui-router states are created in the application configuration, and I did so in the app.js file.

I tried to have some of the organization of the Angular part of the project mimic Rails and its RESTful conventions - such as having a sketches index page, a sketch show page, and reusing the sketch form for creation and updating. Each page has a controller associated with it to handle the unique functionality requirements.

In addition, I have a couple Angular components that act as partials used in repeaters. There’s an artist component displaying an artist’s name, information, and link to artist show page, as well as a similar component for sketches.

I put all the logic for actually communicating to the back end in various Angular services - such as SketchesService for creating and retrieving sketches, and TagsService for creating and retrieving tags. The services use $http to make GET, POST, PUT, and DELETE requests to interact with the back end models via AJAX.

Overall, I found this to be a challenging project, not just due to the complexity of Angular itself, but also due to all the work required to get Angular and Rails to work effectively together.

You can see the source code for the project here on Github.

There’s a lot of data out there on the Internet. We can access the data that other providers make available by consuming their APIs. An API - or application protocol interface - is a way to serve and access data. Accessing data from other sources allows you to use their data to build on their services, provide additional functionality, and use their data in new and inventive ways. This is an external API.

However, internal APIs are just as common. This makes data more accessible to our own application and associated services, something that’s especially useful when using AJAX and JavaScript frameworks. Building an API in Rails is often a straightforward process, especially when the model is simple, since Rails has tools to make the data available in different formats.

JSON

Data available through APIs, internal or external, often comes in the form of JSON, or JavaScript Object Notation. It’s a standard format used for efficient readability - both for developers and parsers. To create an API in Rails, all we have to do is take the data from a model and serialize it - or turn it into JSON data. We can do that using the .to_json method.

# posts_controller.rb
# ...
 def post_data
   post = Post.find(params[:id])
   render json: post.to_json
 end

Here, Rails takes the post and converts it to JSON to be served. We can serve different formats using respond_to. We can also limit the data we’re serving and include associations as well.

# posts_controller
# ...
 def show
   @post = Post.find(params[:id])
   respond_to do |format|
     format.html { render :show }
     format.json { render json: @post.to_json(only: [:title, :description, :id],
                             include: [author: { only: [:name]}]) }
   end
 end

However, as things get more complicated, we might want to find a cleaner way. We can instead use ActiveModel Serializers. You include and install the gem, run rails g serializer <model name>, and modify the attributes in the new serializer class file. Then, when we respond with JSON data, it serializes the model implicitly.

So now you can just do:

# posts_controller.rb
# ...
def show
   @post = Post.find(params[:id])
   respond_to do |format|
     format.html { render :show }
     format.json { render json: @post}
   end
 end
 

Now when you build a JavaScript front end that wants to make dynamic AJAX requests without reloading, you can do that by accessing these serializer-enabled controller actions.

You can read more about Rails ActiveModel Serializers in the Rails Guides.

Using a combination of Rails templates and jQuery, we can create a decent interactive front end for our applications. But this process can quickly become ugly and limited, devolving into a mess of ERB tags and JavaScript functions. This is one of the reasons for the evolution of front end frameworks, one of them being the Google backed Angular JS.

Angular exists to help developers build single-page applications. It provides structure and tools to help solve common problems without having to reinvent the wheel with every application.

Without JavaScript and JS frameworks, everything is rendered on the server. For example, through the MVC paradigm of Rails, the controller renders a view and sends it back as a response. But if you want to make make small changes and see different results - such as adjusting the price range while shopping for a product - you would have to initiate a page reload with every request.

With Angular, not only does it handle routing so you can load different pages without a page reload, it allows you to build dynamic views that react to your input spontaneously.

MVVM

While Rails utilizes the MVC paradigm - model, view controller - Angular utilizes MVVM - model, view, viewmodel. The controller is replaced with the viewmodel, which is responsible for all view logic.

Data Binding

In order to create views that are dynamic and respond to user input, the concept of data binding is employed. This means that data from one source - such as an input field - is bound to something else - like a text box - so it displays your text spontaneously, something that couldn’t really be done in Rails without JavaScript.

In addition, two way data binding is used to keep data from a view synchronized with the data in a model. You can read more about data binding here on the Angular docs.

Angular is an extensive framework with a lot of moving parts. You can delve deeper by taking a look at the Angular documentation.

When building a web application, usually we want some capacity for a user to create an account, login, and then interact with the site in a way that’s tied to their identity. If you login to Amazon, it loads up your cart with the items you selected earlier. If you login to Facebook, it loads your profile and your friends. This is something we take for granted - it’s something that’s always there and just “works.”

But HTTP is stateless. Meaning, you send a request to the server, it sends you a response, and that interaction is done. The server doesn’t remember you solely based on the request. So how can we get the server to remember us so we don’t have to login with every request we send?

Cookies

A cookie is just a string that’s stored on your computer with information identifying you and your interaction with a specific site. When you make a request to the server, data is drawn from the cookie and put into the request header when it’s sent. This information gives the server a way to know that the request is coming from you.

In Rails, you can use cookies via sessions. A session is a hash that you can use to store data for a particular interaction with a user. Rails serializes the data in this hash and turns it into a cookie.

Here’s an example:

# set user_id
session[:user_id] = @user.id

# load the user referenced in the session
@user = session[:user_id]

Since the cookie is just a string, a user could theoretically manipulate the string before sending it back. To prevent this, Rails cryptographically signs the cookie to ensure it’s authentic and untampered with.

Authentication

So how would we make sure the user is logged in before serving any data? This could be a simple implementation using session:

class DocumentsController < ApplicationController
  before_action :require_login

  def show
    @document = Document.find(params[:id])
  end

  def index
  end

  def create
    @document = Document.create(author_id: user_id)
  end

  private

  def require_login
    return head(:forbidden) unless session.include? :user_id   
  end
end

Authentication is usually a complex process involving securely storing passwords, checking if the user entered the correct password, and it also entails dealing with new user registration and destroying your session by logging out. For me, I prefer not having to rewrite this boilerplate functionality for every project, so usually I just use the Devise gem.

Once set up, it handles all of these issues and it’s quite heavily used and tested so you can rest assured that it’s secure. Once you understand the basics of how sessions and authentication work, we can outsource this functionality to a gem like Devise.

You can read more about sessions in the Rails Guides.

With Rails, I’ve been working a lot on dealing with the back end through ActiveRecord and using Rails templates with form helpers. However, modern web applications focus on spontaneous interaction, meaning single page apps with no page reloads. There are a variety of front end frameworks - like Angular, which I will be working with later - that many of the websites we use every day are built with. However, it’s possible to create interactive applications solely with jQuery - a JavaScript library that most websites leverage in one way or another.

For this project, I wanted to create a simple note taking application kind of like Google Keep where the user can create and display notes without reloading the page. This creates a smoother, more natural user experience that I achieved with a jQuery front end.

Rails Back End

Before focusing on user interaction, I organized the back end using Rails controllers and models. I used Devise to set up a user model and authentication since notes wouldn’t be public - they needed to be limited to an individual user. After that, I used rails generate resource to generate the files for notes and tags. The controllers are set up similarly to those in my last Rails project, with the exception of needing to account for the AJAX requests that would be coming from the jQuery front end.

AJAX stands for Asynchronous JavaScript and XML, but most of the time it’s used with JavaScript as XML has become deprecated in favor of JSON - JavaScript Object Notation.

Here is an example of an action in the notes controller handling both HTML and JSON requests:

def show
  @note = Note.find(params[:id])
  respond_to do |format|
   format.html { render :show }
   format.json { render json: @note }
 end
end

With respond_to, we’re able to handle requests for different formats. If we have a link that makes an HTML request for a note, we render the note template. However, if we get a request for JSON, we render the note in serialized JSON format.

What is serialization and how does Rails do it? There are a variety of ways, but I used ActiveModel Serializers which implicitly turns @note into JSON data.

You can take a look at my controllers here. Once the back end is set up, we can move on.

jQuery Front End

There’s a lot of code that went into seemingly basic functionality such as creating new notes, displaying notes based on a tag, and pagination without reloading. I’ll go over some of it briefly.

This portion of code attaches an event listener to the new tag form and processes the request to create a new form:

function attachListeners(){
  //create new tag
  $('form#new_tag').submit(function(event) {
    event.preventDefault(); //prevent form from submitting the default way and reloading page

    var name = $('#tag_name').val();

    if (validator.validateTag(name)) {
      var values = $(this).serialize();
      var posting = $.post('/tags', values);

      posting.done(function(data) {
        $('form #tag_name').val(''); //clear form input
        loadTags();
      });
    }
  });

.........
}

event.preventDefault() is necessary in order to prevent the default behavior of the form, which is to submit and reload the page. Anything with a $ is shorthand for jQuery, so it’s invoking a jQuery object or function. var name = $('#tag_name').val() gets the tag name value from the text input of the form and sets it to a variable. It validates it client side with a custom Validator class and if the data passes, it processes the request.

var values = $(this).serialize() serializes the data in the form via jQuery and prepares it to be sent. var posting = $.post('/tags', values) makes a jQuery POST request to the tags controller with the data from the form that has been serialized. Once the posting is finished, we set a .done callback to clear the form input field and then call the loadTags() function.

function loadTags(){
  $.getJSON('/tags').success(function(response){
    var tags = response;

    $('div#tags').html(''); //clear tags

    for(var i = 0; i < tags.length; i++){
      $('div#tags').append(generateTagLink(tags[i]));
    }

    addTagListeners();
  });
}

Here, we make a jQuery .getJSON request to ask for JSON data from our tags controller. Since we set it up with a respond_to earlier, the controller uses ActiveModel Serializers to send the tag model as serialized JSON data to jQuery. Yes, this is a lot of serialization back and forth, but it’s necessary if we want two way AJAX communication between our front and back ends.

We get our tags as JSON data and iterate through it to generate the HTML necessary to display each tag. From there, we call the addTagListeners() function to add click events to each tag, so when we click on a tag it will then make another AJAX request to get all the notes associated with the clicked tag.

There’s a lot more to it, but this gives a good sense of the basics of the project. You can take a look at the JavaScript portion of the project here and explore some of the additional functionality yourself.

You can see the source code for the whole project here on Github.

Mitul Mistry

Mitul Mistry
I’m Mitul Mistry, a full-stack developer and designer. Contact me here: MitulMistryDev@gmail.com