In this tutorial I will be guiding you through the process of building a full-stack CRUD application with React and a Ruby Sinatra API.
What is Sinatra?
Sinatra is a free open source library and domain-specific language written in Ruby, is a good alternative to Ruby on Rails, and is dependent on the Rack web server interface. Sinatra is considered a 'microframework' and focuses on "quickly creating web applications in Ruby with minimal effort" -sinatrarb.com
What is React?
React is a free open-source front-end JavaScript library built by facebook for building user interfaces based on UI components. It can be used as a base in the development of single-page applications.
What is CRUD?
CREATE, READ UPDATE, and DELETE are the database commands that make up the foundations of CRUD
Routes used in my application:
Name | Method | Route | Purpose |
---|---|---|---|
Create | POST | /model | Creates a new record |
Read | GET | /model | Reads & retrieves data based on input parameters |
Update | PUT/PATCH | /model/:id | Updates data without overwriting it |
Destroy | DELETE | /model/:id | Removes data from the database |
CRUD will be used in this application as a means to retrieve data, create new data, and allow the user to interact with it by editing and deleting the data. I will be using my project from Flatiron School as an example, which is a Job Board application for quick gigs called "Quicky".
Back-End
First a file tour!
The config.ru file is set up so that when the file is run it will require the Environment file, which will make sure there is a connection to the database and then run the ApplicationController which is a class that inherits from the Sinatra gem (base module from within that gem), which contains some starter methods in the controller for you.
Gemfile:
config.ru:
environment.rb:
Rakefile:
Corneal-new
To start my backend I used the Corneal-new: gem that creates a Sinatra skeleton for you to easily build off of when coding your application.
Install the gem, run 'corneal new APP-NAME', and run 'bundle install'. You can start up the server by typing 'shotgun' into the terminal and verify everything is working.
In the terminal run 'corneal scaffold modelName' to create a model and migration for you to create the table for the model, and controller for the model as well.
Database Migrations
Once your specify the attributes you want in your model table run "rake db:migrate" in the terminal in order to run your migrations. Doing this creates a schema file which is a list of logical structures of your data. If you make a mistake and need to edit your migration run "rake db:rollback" then make your edit and run "rake db:migrate" again to run the migration again (simply editing after the fact will not change the schema).
migration files:
Active Record Associations
Once you create your migration files build out your models in order to establish you Active Record associations, for my application I had a one-to-many relationship meaning a Category has many Listings and a listing belongs to a category (has one category):
class Cat < ActiveRecord::Base
has_many :listings
end
class Listing < ActiveRecord::Base
belongs_to :cat
end
Controllers
From here you can start with your CRUD in your controllers. A good place to start would be with a "Read" route which should return all categories when a get request is sent to '/cats'.
Read (GET)
- to view go to http://127.0.0.1:9393/cats in your browser(when you run shotgun it will provide a url for you in the terminal)
#RUBY BACKEND
#Request type is specified before URL endpoint.
#URL endpoint points to all categories
get "/cats" do
# return all categories posts after request
#Requests turned to JSON, for REACT readability.
cats = Cat.all
cats.to_json
end
Read (GET)
- to view go to http://127.0.0.1:9393/:id
- this route allows you to see an individual category based on the id you provide in the url
get '/cats/:id' do
cat = Cat.find_by_id(params[:id])
cat.to_json
end
Creat(POST)
- This route typically receives information in the request body and creates a new data entry which the user can do from the browser by interacting with the front-end
post "/cats" do
cat = Cat.create(
job_type: params[:job_type]
)
cat.to_json
end
Update (PATCH)
- This route receives the id of the category which is being updated in the url and is then updated using the data passed in via the request body
patch '/dats/:id' do
cat = Cat.find(params[:id])
cat.update(
job_type: params[:job_type]
)
cat.to_json)
end
DELETE
- This route takes an id of a category to be deleted in the url and then deletes it using the .destroy method
delete '/cats/:id' do
category = Cat.find(params[:id])
category.destroy
end
These are basic examples of CRUD routes and functionality you can implement into your applications. Here are both of my controllers to give you an idea of other options you can build into your application
Front-End
For this section of the project I will explain how to build out your front-end to connect with your back-end. This tutorial is assuming you know React but simply need help connecting your front-end to your back-end.
Run 'npx create-react-app my-app' in the terminal to create a quick skeleton of all the file structures you need to begin building out your front end. Build your components out as you would like for what makes sense for your specific project.
Read(GET)
useEffect(() => {
fetch("http://localhost:9393/cats")
.then((r) => r.json())
.then((data) => {
setCats(data);
});
}, []);
Create(POST)
const configObj = {
method: "POST",
headers: {
Accept: "application/json",
"Content-Type": "application/json",
},
body: JSON.stringify({
job_type: jobType
}),
};
const handleSubmit = (e) => {
e.preventDefault();
fetch("http://localhost:9393/cats", configObj)
.then((r) => r.json())
.then((cat) => {
addNewCategory(cat);
});
};
*Update(PATCH) *
function handleEditCategory(e) {
e.preventDefault();
fetch(`http://localhost:9393/cats/${id}`, {
method: "PATCH",
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(formData),
})
.then ((response) => response.json())
.then((updatedCategory) => {
handleUpdateCategory(updatedCategory);
});
}
DELETE
const handleDelete = () => {
fetch(`http://localhost:9393/cats/${id}`, {
method: 'DELETE',
});
const updatedCats = cats.filter((cat) => cat.id !== id);
setCats(updatedCats);
};
Hopefully this tutorial has been helpful in guiding you on how to start building full-stack applications. Here's a link to the front-end and back-end GitHub repositories for my application.
Top comments (0)