I Made A JavaScript Single Page Application And This Is What I Learned
By: John Troutman
Tags: Coding, Flatiron School, Programming, JavaScript, Software Development

For the penultimate project in the Flatiron School software engineering program I had to create a single page application with JavaScript handling the frontend and Rails used as an API for the backend. These are the important things I want to convey to anyone else that is building something with this framework.

JavaScript fetch calls and Rails mass assignment

I cannot stress the importance of knowing how mass assignment works in Rails for sending information from the JavaScript frontend to the Rails backend. Knowing how to structure the body parameter within the fetch call can make creating new instances of models and their children much easier. For sake of example let’s say the models are:

Lists have a title and Items have a name. To create a new list and multiple items for that list with input from the user on the frontend we will need to use the fetch() method and make sure we tell it we are using the POST method. The body parameter is where the magic happens. If you recall from the List class above it has the accepts_nested_attributes_for class method. This will define an attribute writer called items_attributes and can be then used in a list_params method like so: params.require(:list).permit(:title, items_attributes: [:name]) . With this in mind, over on the frontend the body of the fetch() call should be structured so that Rails can take this information and create everything at once with mass assignment.

If done correctly you can send the fetch() call to /lists and in the controller method lists#create make a new list and 5 new items associated with it and save them all to the database at once. This knowledge of Rails helps with sending information to the backend but what about receiving information and using it for your frontend application?

2. Rails rendering with serializers

If we are looking at retrieving a set of lists and their associated items they are gathered in the lists controller in Rails. Then they are rendered in JSON so that the frontend can use that information to be displayed in the DOM. The most efficient way of doing this, so as to allow only the data you want without any unwanted excess, is to create a serializer class.

When lists are gathered in the controller they can then be rendered with the ListSerializer:

This will render all the lists in the database at the /lists address in JSON for the frontend to gather. Notice that it includes the lists associated items along with the item’s id and name attributes while excluding the :created_at and :updated_at columns in the list database. Since the list model is using the has_many :items association it gains the List.items association method that we are then able to use within the ListSerializer class to render the items along with the lists.

This all works great so long as you are fine with rendering the items in the order they were created but what if you wanted them ordered another way such as alphabetical order? First, create an instance method to handle the sorting within the List model:

Now we can take the items_sorted method and pop it into the ListSerializer.

The items will now be rendered in alphabetical order! Any instance method that sorts associations will work for this as long as you use the method name in the serializer. This all may be obvious to some people but it was something I discovered when tinkering around with the data for my project. It’s much easier to have the data already organized when it is rendered from Rails than to try to organize it on the frontend with JavaScript.

3. When stuck, don’t forget to check the simple stuff first

For the final example, I will present a personal anecdote. What I am about to convey may be painfully obvious to many readers. In most cases I do not fall into the trap I will soon divulge but sometimes I still find myself jumping past the little things and trying to find an overcomplicated solution to what ends up being an embarrassingly simple problem. In fact, I got burned by it during this project and ended up pulling my hair out in front of the computer for a comically extended amount of time. When I finally realized the problem and how enormously simple it was I literally laughed out loud at the situation and myself for letting it go on for as long as it did. It was a humbling ordeal and one that, again, maybe extremely obvious to the majority of people reading this but one that I feel pops up often enough when coding that deserves a mention.

I had written the code to submit a form element consisting of inputs and a select element. This meant an event listener attached to a button, that when clicked, would call a fetch() method to send the form information to the backend Rails API, create the necessary models and save them to the database, and then render these new models in JSON which could then be snatched up on the frontend and displayed in the DOM. The problem was when the submit button was clicked the models would be created and saved on the backend but nothing would display on the page. Because the problem seemed to lie solely within the frontend I immediately jumped to the promise fulfillment then() method and the functions I had created and invoked within to display the model data on the page. I could not see anything wrong and there were no errors within the console to give me an indication as to what was going wrong. I tinkered with my functions that would handle manipulating the DOM to no avail and read over the code starting with the fetch() call repeatedly until my eyes were glossy.

After taking a nice break (another obvious but helpful tip!) I finally decided to look at the very beginning of this sequence starting with the event listener on the submit button. That was when I noticed in the callback function of the event listener I did not have preventDefault() within it. Since I was not using the standard HTML form submission and did not provide an action within the form element itself this function is necessary to stop the page from trying to submit the form data normally. Once I corrected this I tried everything again and *drum roll*…. it still didn’t work. All was not lost however as I was now getting a “variable is not defined” error in the console. Looking up the line of code the error referenced I noticed immediately that I had misspelled a variable I was using as a parameter for a function call. Two very small and simple mistakes took up way more time to fix than they should have. The lesson here is to not forget to start simple. It almost happens instinctually to try to jump past the easy stuff, whether because you figure those things are too simple to mess up or that the problem must be where things are more complex. The simple things take up hardly any time to check so even if the problem isn’t there you aren’t losing much by checking there first.

Like any coding project, this was a learning experience and one that I felt rewarded by in many ways. I feel proud of what I was able to create but also have a new focus on what my strengths and weaknesses are as a developer. As I move on to the final section in the Flatiron program I am feeling good about the progress I have made and excited about all the future projects I will work on.

More content at plainenglish.io