Adding jQuery to My Rails Project

C Miller
C Miller
Jul 25, 2017 · 4 min read

For the final project in the Rails and JavaScript section of my learn.co bootcamp, we expanded upon our previous Rails Project. The goal is to add dynamic features by using jQuery and a JSON API.

College-Todo: Screenshot of User profile page

Project Requirements:

  1. Must render at least one index and one show page via jQuery and an Active Model Serialization JSON backend.
  2. The rails API must reveal at least one has-many relationship in the JSON that is then rendered to the page.
  3. Must use your Rails API and a form to create a resource and render the response without a page refresh.
  4. Must translate the JSON responses into Javascript Model Objects. The Model Objects must have at least one method on the prototype.
  5. Do NOT use remote: true in this application.

Serializing JSON responses

First I installed ’active_model_serializers’ gem. ActiveModel::Serializer allows you to define which attributes and relationships you wish to include in your JSON response. It also acts as a presenter where you can define custom methods to control the format of your JSON response. For example I used custom methods to format my created_at timestamp.

class StorySerializer < ActiveModel::Serializer
attributes :id,:title,:content,:slug,:created_at,:comments_count
has_one :user, serializer: StoryUserSerializer
has_many :comments, serializer: StoryCommentSerializer
has_many :tags
def comments_count
object.comments.count
end
def created_at
object.created_at.strftime("%a %m-%d-%Y")
end
end

Rendering index and show pages via jQuery and JSON

I chose to display all stories on the story index page with links to individual story show pages, using the serializer data to render the information on my index and show pages. An AJAX GET request fetches the stories, backend renders the stories in JSON format, and then appends the stories to the page.

In order for the JSON request to work I had to configure my controllers. The controllers need to respond to the JSON requests, so I added the necessary code. For example in my story controller, I added respond_to JSON format to the index, show, create, and update methods.

//code snippet from my Story controller
class StoriesController < ApplicationController
before_action :authenticate_user!
before_action :set_story, only: [:show, :edit, :update, :destroy]
before_action :owned_story, only: [:edit, :update, :destroy]
def index
@stories = Story.order(created_at: :desc).page(params[:page])
@tags = Tag.all
respond_to do |format|
format.html { render :index }
format.json { render json: @stories }
end
end
def most_comments
@stories = Story.most_comments.page(params[:page])
@tags = Tag.all
respond_to do |format|
format.html { render :index }
format.json { render json: @stories }
end
end
def show
@tags = @story.tags
@comment = Comment.new
@comments = @story.comments.order('created_at')
respond_to do |format|
format.html { render :show }
format.json { render json: @story }
end
end
end

Using my Rails API to create a resource and render without a page refresh

Now I wanted users to create and delete comments on the story show page without a page refresh. One problem I ran into was with turbolinks. My pages were not rendering without a hard refresh, so I ended up disabling turbolinks.

Steps to remove Turbolinks:

  1. remove gem ‘turbolinks’ from gemfile
  2. remove //= require turbolinks from application.js
  3. remove ‘data-turbolinks-track’:’reload’ from javascript_include_tag in application.html.erb
  4. then run bundle install and restart server

Another problem I encountered happened when pressing the back button in the browser, the browser rendered raw json data. To prevent this from happening, I used ajaxSetup to set cache=false when the page loads. The browser was caching, then retrieving the last request which was JSON.

$(function(){     $.ajaxSetup({
cache: false,
});
})

You can also set cache=false explicitly in an $ajax request. For most jQuery AJAX requests, default cache = true with the exceptions of datatype = ‘script’ and datatype = ‘jsonp’.

After removing turbolinks and setting the cache to false, my pages were loading and the back button was rendering the correct information and format.

Javascript Model Objects

To meet the final requirement, I needed to translate my JSON response into Javascript Model Objects.

So instead of taking the JSON response of the created comment and appending it to the DOM, I created a Comment prototype object and used it to append the comment to the DOM.

//Code snippet from my comments.js filevar Comment = function(attributes) {
this.id = attributes.id;
this.content = attributes.content;
this.user = attributes.user;
this.created_at = attributes.created_at;
};
Comment.prototype.deleteLink = function() {
var output = '<a class="btn btn-danger btn-xs" data-confirm="Are you sure you want to delete?" rel="nofollow" data-method="delete" href="/stories/:story_id/comments/' + this.id + '">';
output += '<span class="glyphicon glyphicon-remove"></span>';
output += '</a>';
return output;
}
Comment.prototype.renderComment = function() {
var html = "";
html += '<ol class="list-unstyled" id="comment-" + comment.id >';
html += '<li><strong>' + this.user.username + '</strong>' + " " + ':' + " " + this.content + " " + this.deleteLink() +'</li>';
html += '</ol>';
return html;
};
var attachListener = function() {
$(document).on('submit', 'form#new_comment', function(event){
event.preventDefault();
var $form = $(this);
var action = $form.attr("action");
var params = $form.serialize();
$.ajax({
url: action,
data: params,
dataType: "json",
method: "POST"
}).success(function(json) {
$(".commentText").val("");
var comment = new Comment(json);
var renderComment = comment.renderComment();
$("#commentSection").append(renderComment);
});
});
}

$(document).ready(function() {
attachListener();
});

The last problem I faced happened while testing the application on other browsers. I found myself unable to login or create a new account, and received the following error — ActionController::InvalidAuthenticityToken in Devise::Sessions#create. After at least 30 minutes of searching Stack Overflow and trying different protect_from_forgery methods, I realized I had unchecked the accept cookies option in my firefox settings. Turned them back on and all worked as it should! Woo-hoo I felt dumb!

This project has taught me a great deal about using Rails, AJAX and jQuery; and helped me solve problems specific to these languages and programming in general. You can find the code to this project on my github page: https://github.com/cmiller36/college-todo-rails. Thanks for reading :)

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade