Ruby...Covered in CRUD.
Tags: ruby, activerecord, sinatra, tutorial
Published: 2022-11-21 01:10:55

Now that we’ve made it past the halfway point at Flatiron, I'm starting to understand a lot more about what blogs are and what their basic utility is, especially for beginners. 

The point of blogs - at least from my perspective at this point - is to find those diamonds in the rough that hold your hand and spell out the little bits of code you‘re missing, or fire up the right light bulbs in your brain to give you the right _ah-HA!_ moment get your program working. Then you copy-paste what you can, curse at the rest, add it to your bookmarks under _Blogs & Stuff_.

But feelings come first. And I've gotta say that starting Ruby was tough, and I think that this phase was probably the one that I struggled the most with, but in that same vein, I also learned the most. It’s gratifying and humbling at the same time, and I’m kind of in love with the feeling, but I digress...

For this entry, I’ll assume that the reader is here for the same things I was looking for during Phase 3, that they also have a fair understanding of Ruby, ActiveRecord, Sinatra, and a sprinkle of SQL, and that really they’re just looking for that diamond...or _ruby_. As such, the following are some helpful snippets that I learned during my back-end brigade. 

---
**DATA MIGRATIONS**

The order of operations for establishing our migrations and creating our tables starts by creating the migration files. Open the terminal and navigate to the project's directory. Once there, type into the console:

`rake db:create_migration create_table_name` 

NOTE: Our table names should be PLURAL, because they are tables, and they hold many instances of a single thing...they are large, they contain multitudes. For example, my group and I created a mock eCommerce website for our final project, and we needed to create a table of data for our ITEMS, so we ran: 

`rake db:create_migration create_items`

This creates a time-stamped migration files that determine how the tables are set up. Inside of those files, we assign data types and the associated symbol to each 'row' of our table. 

For example, for our Items table, we needed a name, price, description, image URL, brand, and category. After creating our migration file, our table looked like this:

![Items Table](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/usr6vvki2a67tdegfzt4.png)

We can assign the data types to whatever we like. Other available types are `float, decimal, numeric, datetime, time, date, timestamp, binary, primary_key, boolean, bigint,` & `text`, but integer and string seem to be the most common in BeginnerLand. And don't forget to add `end` at the end of the `create_table` method! Once our tables are all set up, run:

`rake db:migrate`

If successful, we should have a new file called `schema.rb` in the db folder. Next, we needed to establish our relationships so our data can get to know each other and be friends. For our project 

![User Relationships](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pzr64ggnmfu8qe4byhbx.png)

![Item Relationships](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/h6bjrm6dxj4uea8875ln.png)

These are 'one-to-many' relationships, as in this ONE ITEM, HAS MANY USERS that leave REVIEWS on it. So for the syntax we say 

`Item has_many :reviews, through: :users` 

...and, as always, we pay extra special attention to where we put our colons. 

![Reviews description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jea5ut6gi3r641kqo8sb.png)

This is our 'many-to-many' relationship. Notice how the use of `item` and `user` are both SINGULAR here! That makes sense - a review can only be for ONE item and can only be written by ONE user. Once these relationships are set up we can create our SQL tables by running this code in the console:

`rake db:migrate`

If we have a seed file, that's amazing. If we don't, I somewhat recommend using [faker](https://github.com/faker-ruby/faker) to help out. It's great for making random seeds, but my project group and I ran into some trouble manipulating the output data as beginners, so I'd say it's handy, but only to a certain degree. Once our seeds are filled in, run:

`rake db:seed`

and that should fill up our SQL tables will some nice juicy data that we can do whatever we like with...well, whatever we know how to do. Which as beginners isn't that much, but WE GOT THIS!

The next step is to set up Sinatra, which you can find much better-explained in their docs [HERE.](https://sinatrarb.com/intro.html)

---
**CREATE, READ, UPDATE, DELETE**

So what about CRUD?! Well, I'm not going to give up _everything_, but it starts with setting up the paths within our application controller. For example:

![Item Methods](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tuvlzdscya86et65knut.png)

Those are simple GET requests. We can check our work using an application like [Postman](https://www.postman.com/downloads/), or by running 

`rake server`

in the terminal, and opening up http://localhost:9292 in the browser, followed by whatever our path name is. For example, to route to our item_all path, we would type into the browser:

`http://localhost:9292/item_all/`

The real money-maker here is the associations within our Object-Oriented-Program. When we pull data using Sinatra ActiveRecord, we can also pull the data that that data is associated with by using `include:`. So, if we make a route to pull a single item's data, we can also pull the _reviews_ for that item AND the _user_ data for those _reviews_, like so:

![Find Item](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jm3lnlzxd9ase20jeuae.png)

This one route now allows us access to literally every bit of data that we added to our tables. That's...super neat y'all.

Now what does this look like on the front end? Well we made a component that displays the details of an individual item, AS WELL AS all the _reviews_ associated with that item, AS WELL AS all of the _user data_ for whatever user wrote the review. We'll need `useState, useEffect` and `useParams` like so: 

![Imports](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/u6xhgocj4zzvgn11qm0p.png)

In our component function we set our `item` state:

![State Setter](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/g0nic35qv06gouczjjfp.png)

Then we implement useEffect and add a catch if we have any trouble rendering our data for any reason. 

![Fetch & Catch](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hbeqn8o207xue2bgrbif.png)

Then after a little destructuring, we can add our data to our JSX...

![Destructuring & Building](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wxl3hbzcl4u5utgryk8o.png)

Sweeeeeeeeeeeeeeeeeeet! Rendering data is so cool. It's trending. Or..._trendering!_ 

---

To get the rest of the CRUD, my project group and I ended up setting the list of item reviews as its own separate component, and then each individual review as a card within the component. So we had Details.js which was a parent of ReviewsList.js, which was a parent of ReviewCard.js. This allowed for us to manipulate all the data we were handling without making a huge mess out of the variable names and turning our Details file into callback hell. When in doubt, make another component.

Figuring out the rest was a matter of passing through the correct data using HTTP in our Application_Controller.rb, making the correct handler functions in the correct React Component, and making sure the fetch was doing everything we needed it to do... 

For DELETE our application_controller.rb path was:
![DELETE Path](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/297ayd09br5kvdxlz6uu.png)

Our HandlerFunction was:
![DELETE Handler](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fszk8cbzqhoszextsgs7.png)

And the accompanying fetch:
![DELETE Fetch](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/du77r35yxk05g9japkqc.png)

---

For POST our path was:
![POST Path](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nf1onlwuvxmolvwcy344.png)

The POST HandlerFunction was:
![POST Handler](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0waeabxfd1rz7tp52upc.png)

And the POST Fetch was:
![POST Fetch](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/s389xlrv0ryfka59nyeh.png)

---

And the tricksiest little Hobbitses of them all...the PATCH path looked like:
![PATCH Path](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ni4q3zlav71p5a7vqnqz.png)

The HandlerFunction was:
![PATCH Handler](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vpij3kwyvflhr2p7zgml.png)

And the Fetch:
![PATCH Fetch](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gsgotj1w7fqqdsu1fb2w.png)

... This, of course, isn't the entirety of the code for our React components, but I think it covers more than enough to get the gears turning, especially for my fellow Flatironeers.

---

And that's it - thanks so much for making it this far! I went lighter on the gifs and heavier on the content this time. 

Hopefully this was helpful, especially to my fellow Flatironeers that are having trouble finding a blog where all of this stuff is literally spelled out for you. That blog now exists!

If you have any questions or recommendations for edits, feel free to reach out. I welcome any and all feedback.

Keep fightin' the good fight! ʕ•ᴥ•ʔ