I set out to build a simple single page application (SPA) which utilized a JavaScript frontend and a Rails API backend in order to store recipes.
I started by setting up the Rails API backend. I navigated to the directory where I wanted to create the project, and then ran the following command in the terminal:
rails new meal-maker --api
The --api
flag set up a Rails application named meal-maker, but without many of the standard features and middleware that Rails would have come with if I had run the command without adding the --api
flag.
With this API-only Rails build set up I then created the models, controllers, and migrations that I would need.
I decided to have two models, a cuisine model and a recipe model with has_many and belongs_to relationship between them where a cuisine has many recipes and a recipe belongs to a cuisine.
To quickly create the migrations, models and controllers for the cuisines and recipes I ran the following two commands in the terminal:
rails g resource cuisine title
rails g resource recipe title image instructions ingredients cuisine:references
The first command created a cuisine migration file to create a cuisines table with a title column with a string data type, along with a cuisine model and a cuisine controller.
The second command created a recipe migration file to create a recipes table with columns for title, image, instructions, and ingredients, all of the string data type, along with a cuisine_id column to indicate the particular cuisine that a recipe belongs to.
In addition a recipe model was created and a recipe controller was created after running the command. My models were set up as follows:
class Cuisine < ApplicationRecord
has_many :recipes
end
class Recipe < ApplicationRecord
belongs_to :cuisine
end
The recipe model already had belongs_to :cuisine
filled in after running the second command above, but for the cuisine model I had to enter has_many :recipes
there myself.
I ran the migrations that had been created using the command rails db:migrate
and also filled out the two controllers with the necessary actions (controller methods) that I would need for the functionality that I wanted my application to have.
I also filled out the seed file with information for four different recipes from four different types of cuisine that I would use to see how the application was working as I was building it out. Then I ran the command rails db:seed
to seed the database with the instances of the cuisine and recipe classes.
In the cors.rb file in the config/initializers folder I made sure that the following code was uncommented out:
Rails.application.config.middleware.insert_before 0, Rack::Cors do
allow do
origins '*'
resource '*',
headers: :any,
methods: [:get, :post, :put, :patch, :delete, :options, :head]
end
end
And I made sure that the line which originally said origins 'example'
was now changed to origins '*'
.
In my Gemfile I also uncommented out the line which had gem 'rack-cors'
commented out. I then ran the command bundle install
in the terminal.
With those changes made to those two files I made sure that problems relating to Cross-Origin Resource Sharing (CORS) would not cause problems for the ability of the JavaScript frontend to communicate with the Rails API backend.
After this I moved all the folders and files in the application except the README.md file into a new folder that I created called "backend".
Then I created a new folder called "frontend" and in that new folder I created an index.html file and a style.css file. In that frontend folder I created another folder called src, and in the src folder I created an index.js file.
In the index.html file I built out all the HTML elements that my application would use, consisting mainly of a form to add new recipes as well as a container to hold already available and newly added recipes.
In the style.css file I defined the visual styling/appearance of the page using CSS, then I made sure that the style.css file was linked to the html file by making sure to include the following line in the <head>
section of the index.html file:
<link rel="stylesheet" type="text/css" href="style.css" />
I also made sure that the index.js file would be linked to the index.html file by including the following line in the <head>
section of the index.html file:
<script type="text/javascript" src="src/index.js" defer></script>
In the index.js file inside of the frontend/src folder I used Object Oriented JavaScript to write out a Recipe class with the methods and behavior that I wanted to provide my application with the necessary functionality.
I wrote static and non-static methods that used DOM manipulation or Document-Object-Model manipulation on the elements of the index.html file, as well as methods that made three AJAX calls using fetch in order to GET and POST data from and to the Rails API backend that I had set up earlier. I was able to communicate with the Rails API backend using fetch
in these JavaScript methods after making sure to first navigate to the backend directory of the application and then use the rails s
command to start the server.
One of these methods I defined for the Recipe class was able to use fetch
to get all of the Recipe objects, including information about what Cuisine each Recipe object belonged to, from the backend and pass on that information to another method to display these recipes on the page. Another method was able to use fetch
to make new Recipe objects from the information entered by the user on the form at the top of the page, and then pass on the entered information to another method which would display this newly created recipe in a table row on the page.
Finally another method was able to remove existing recipes from the page of the application and use fetch
to delete existing recipes from the Rails API backend once the user clicked on the delete button below a recipe. All of this functionality was possible in the application without the page needing to be refreshed/reloaded, showing the power of a JavaScript frontend to deliver a fast and seamless experience for the user.
I learned a great deal about JavaScript, HTML, and CSS from building out this project and I felt like I was closer to becoming a full stack software developer after it was completed.
Top comments (0)