<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: marisa saunders</title>
    <description>The latest articles on DEV Community by marisa saunders (@marisa-saunders).</description>
    <link>https://dev.to/marisa-saunders</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F797782%2F62233d0a-09d8-447d-b5df-874e198d6356.png</url>
      <title>DEV Community: marisa saunders</title>
      <link>https://dev.to/marisa-saunders</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/marisa-saunders"/>
    <language>en</language>
    <item>
      <title>How to setup active storage w/ AWS S3</title>
      <dc:creator>marisa saunders</dc:creator>
      <pubDate>Wed, 06 Sep 2023 20:10:45 +0000</pubDate>
      <link>https://dev.to/marisa-saunders/how-to-setup-active-storage-w-aws-s3-gcl</link>
      <guid>https://dev.to/marisa-saunders/how-to-setup-active-storage-w-aws-s3-gcl</guid>
      <description>&lt;p&gt;For my final project at Flatiron School we had to add some new technology to our project that we had never used or learned about before and I decided on using Active Storage with AWS S3 to allow a user to upload an avatar. Upon researching, reading blogs, documentation, and watching online tutorials I found that I was having to use many different resources just to figure out how to get started, and therefor have decided to write a step by step tutorial all in one place for whoever needs to get started with Active Storage. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;u&gt;Active Storage setup&lt;/u&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;First things first, I recommend reading the active storage documentation in rails or at least referencing it if you find that you are having any issues: &lt;a href="https://guides.rubyonrails.org/active_storage_overview.html"&gt;https://guides.rubyonrails.org/active_storage_overview.html&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;but I will lay out the necessary steps for you here as well. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;install "libvips" or "ImageMagick" for image analysis and transformations&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;both of these require the image_processing gem so uncomment it in your Gemfile or add it if you don't see it there already: &lt;br&gt;
&lt;code&gt;gem "image_processing", "&amp;gt;= 1.2"&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Active storage uses three tables in your database: &lt;br&gt;
• active_storage_blobs&lt;br&gt;
• active_storage_variant_records&lt;br&gt;
• active_storage_attachments&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;to create these tables run "bin/rails active_storage:install" and after migrate them by running "bin/rails db:migrate" &lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here is a photo of my schema file for reference for how yours should look (note please ignore the "photo" column in my users table I had this here as a temporary column for when I was working on the project before I had implemented Active Storage) &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Lxa4lSHQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/u97b45a2p5tt1h1ejdyo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Lxa4lSHQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/u97b45a2p5tt1h1ejdyo.png" alt="Image description" width="800" height="1424"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Declare active storage services in "config/storage.yml"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--FqpOCod5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hn4u4y5gh577wvzmnl8y.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--FqpOCod5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hn4u4y5gh577wvzmnl8y.png" alt="Image description" width="800" height="382"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In "config/environments/development" tell Active Storage which service to use&lt;br&gt;
&lt;code&gt;config.active_storage.service = :local&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;To use the S3 service in production add this line of code to "config/environments/production"&lt;br&gt;
&lt;code&gt;config.active_storage.service = :amazon&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;To use the test service add this line of code to "config/environments/test"&lt;br&gt;
&lt;code&gt;config.active_storage.service = :test&lt;/code&gt; &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;u&gt;Setting up your Models, Controllers, and Serializers&lt;/u&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Since I was adding the ability for a user to upload an avatar when creating an account I added the following line of code to my user model: &lt;br&gt;
&lt;code&gt;has_one_attached :image&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;this line of code is very important and establishes the association, do not be confused that this will not be reflected as a column in your schema file &lt;/p&gt;

&lt;p&gt;Add the "with_attached_image" method to you Users Controller:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--UQo_Ckv---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ev2jc6gkmfbmrttlcgn7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--UQo_Ckv---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ev2jc6gkmfbmrttlcgn7.png" alt="Image description" width="614" height="172"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;and make sure to include ":image" into your user params&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--yq2IIXb---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6kzqt9bet69gba6clewy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--yq2IIXb---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6kzqt9bet69gba6clewy.png" alt="Image description" width="686" height="158"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Modify your User Serializer like so:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--eQm-ytJE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4av3cwpp5hl9slvxds7b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--eQm-ytJE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4av3cwpp5hl9slvxds7b.png" alt="Image description" width="800" height="325"&gt;&lt;/a&gt;&lt;br&gt;
(adding ":image" to attributes and the "image" custom method)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;u&gt;Setting up AWS&lt;/u&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;make sure your service in config/storage.yml set to "S3"&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;add the "aws-sdk-s3" gem to your gemfile&lt;br&gt;
&lt;code&gt;gem 'aws-sdk-s3', require: false&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Create an AWS account and create a bucket in S3 (you can change your bucket name in "config/storage.yml" to your specific bucket name once we create the bucket, and the region to whatever your specific region once we select it in AWS S3&lt;/p&gt;

&lt;p&gt;Once you're logged in click on "S3"&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--7tNdNXb0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/80gkgo7qb6g14rxgnf95.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--7tNdNXb0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/80gkgo7qb6g14rxgnf95.png" alt="Image description" width="800" height="512"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click "Create Bucket"&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--_wB5QwE3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wnhgo69k77e0kkcswl5a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--_wB5QwE3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wnhgo69k77e0kkcswl5a.png" alt="Image description" width="800" height="254"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You will be taken to this page:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--RtTE48GD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2jsqdh0z0qhz45uxejgh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--RtTE48GD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2jsqdh0z0qhz45uxejgh.png" alt="Image description" width="800" height="1256"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Fill in the form as so: &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Bucket name&lt;/strong&gt; - yourbucketname&lt;br&gt;
&lt;strong&gt;AWS Region&lt;/strong&gt; - your region&lt;br&gt;
&lt;strong&gt;Object Ownership&lt;/strong&gt; - ACLS disables&lt;br&gt;
&lt;strong&gt;Block Public Access settings for this bucket&lt;/strong&gt; - Block all public access&lt;br&gt;
&lt;strong&gt;Bucket Versioning&lt;/strong&gt; - Disable&lt;br&gt;
&lt;strong&gt;Tags&lt;/strong&gt; - leave empty&lt;br&gt;
&lt;strong&gt;Default encryption&lt;/strong&gt; - Server-side encryption w/ Amazon S3 managed keys(SSE-S3)&lt;br&gt;
&lt;strong&gt;Bucket Key&lt;/strong&gt; - Enable&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;for more information and understanding on why you should set "Object Ownership" and Public access settings a certain way I recommend watching this video: &lt;a href="https://www.youtube.com/watch?v=UOLpv2f8mz8&amp;amp;t=779s"&gt;https://www.youtube.com/watch?v=UOLpv2f8mz8&amp;amp;t=779s&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once you are done click "create bucket" &lt;/p&gt;

&lt;p&gt;Click on the name of your new bucket where you will now be taken to a page where you can edit your settings&lt;/p&gt;

&lt;p&gt;Click on permissions and scroll to the Bucket Policy section and click on the "edit" button and then the "Policy Generator" button. &lt;/p&gt;

&lt;p&gt;Fill out the form as so: &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Select Type of Policy&lt;/strong&gt; - S3 Bucket Policy&lt;br&gt;
&lt;strong&gt;Effect&lt;/strong&gt; - Allow&lt;br&gt;
&lt;strong&gt;Principal&lt;/strong&gt; - arn:aws:iam::ACCOUNT_ID:root&lt;br&gt;
&lt;strong&gt;AWS Service&lt;/strong&gt; - Amazon S3&lt;br&gt;
&lt;strong&gt;Actions&lt;/strong&gt; - DeleteObject, GetObject, PutObject&lt;br&gt;
&lt;strong&gt;Amazon Resource Name (ARN)&lt;/strong&gt; - arn:aws:s3:::BUCKET_NAME/*&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;To find your account ID click your username in the top right corner and your account id will appear&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;you can find your ARN in the properties section of the settings&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--_D8NtLcQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qsf0sjb713cfaymaa1ih.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--_D8NtLcQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qsf0sjb713cfaymaa1ih.png" alt="Image description" width="800" height="165"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once you have filled out the form click "Add Statement" and "Generate Policy" and copy the Policy JSON Document code that pops up and paste it into the field under Edit Bucket Policy and click "Save Changes" here's a photo of mine for reference: &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--JQr4qqTF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/er1je2hzcnxib1lqzvim.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--JQr4qqTF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/er1je2hzcnxib1lqzvim.png" alt="Image description" width="800" height="901"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next, go back to your bucket and go to the permissions section where you can scroll down to CORS(Cross-origin resource sharing) and click the "edit" button. Here's mine for reference: &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--X872P_VV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qzmx64xrcha6esxmfu1v.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--X872P_VV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qzmx64xrcha6esxmfu1v.png" alt="Image description" width="800" height="394"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can add more methods if you need depending on your app and if you plan to deploy your application you will need to do something like this: &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--H_au7bq7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kt0063vbv9l7l82zf2db.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--H_au7bq7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kt0063vbv9l7l82zf2db.png" alt="Image description" width="800" height="802"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now that all of this is saved and complete, click on your username in the top right corner and then click on "security credentials" and then "users" on the left side of the page and click "create user" in the top right corner&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--iC-zLl3L--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cm0f95pdpjivab6c1pef.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--iC-zLl3L--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cm0f95pdpjivab6c1pef.png" alt="Image description" width="800" height="265"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The name of the user does not matter or need to be connected to an existing user in your application so I would just name it something generic&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once you enter your user's name click "next" and fill out the form like so: &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Permission options&lt;/strong&gt; - Attach policies directly &lt;br&gt;
&lt;strong&gt;Permission Policies&lt;/strong&gt; - AmazonS3FullAccess&lt;/p&gt;

&lt;p&gt;Click "Create User" to save your new user and then click on the name of your new user and then "Security Credentials" where you can scroll down to the Access Keys section and click "Create Access Key" &lt;/p&gt;

&lt;p&gt;Select "Application running outside AWS" and add a create description tag called something like "Connect AWS S3 to my_app_name". You will now be able to see your access keys, keep this window open and take a screen shot or download them to a CSV file because once you close this page you wont be able to access them again and you will need them to make connections to your app&lt;/p&gt;

&lt;p&gt;In your terminal run: "EDITOR=vim bin/rails credentials:edit"&lt;br&gt;
and edit/update "aws", "access_key_id", and "secret_access_key" with the information in the CSV file you just downloaded after we created the access keys above, once you are done close the file and it will automatically save and you can leave the terminal and you are good to go! &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;u&gt;Setting up your Frontend&lt;/u&gt;&lt;/strong&gt;&lt;br&gt;
All of my research led me to use Javascript' formData api as a way to allow the user to upload a photo on the frontend through a form which would then connect to the backend  to Active Storage. Here is my signup function and handleSubmit function which is attached to the onSubmit on my form&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--PlCnqo5C--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bundljdg9q9gwn23l9e3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--PlCnqo5C--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bundljdg9q9gwn23l9e3.png" alt="Image description" width="800" height="1133"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;When working on this project and troubleshooting I made the mistake of adding a header to my POST method so make sure not to do so &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Instead of using "e.target.value" like you are most likely using in the rest of your form you will instead need to use "e.target.files" on the image (I am using React Bootstrap if you are confused as to why my form looks like like this) &lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--6IJRX4Ef--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/210lmzyb1nfkt6eps3in.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6IJRX4Ef--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/210lmzyb1nfkt6eps3in.png" alt="Image description" width="800" height="339"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you are using validations in your project I found that the way params was sent back for the image using formData was creating some issues. To resolve this I had to create frontend validations for the image in the form as a workaround to prevent my app from breaking. I am sure there are alternative ways to do this, this is just the option that worked for me. In order to do this I created a new state object: &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--YPcLAanX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8vcogjfn46c67a3zaquz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--YPcLAanX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8vcogjfn46c67a3zaquz.png" alt="Image description" width="672" height="40"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;and then a conditional statement: "isImage ?" in my form like so: &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--L1GCwHgn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uhz6hau4zuu0otfms2ud.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--L1GCwHgn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uhz6hau4zuu0otfms2ud.png" alt="Image description" width="800" height="1542"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;u&gt;Conclusion&lt;/u&gt;&lt;/strong&gt;&lt;br&gt;
I hope this was helpful, of course aspects of this tutorial are specific to my project but I think they can easily be adjusted and manipulated to the specifics of yours. I tried to  get into the obstacles and troubleshooting I had to figure out along the way incase you find yourself in the same position! &lt;/p&gt;

</description>
    </item>
    <item>
      <title>How to update React state on nested objects that are serialized in Rails</title>
      <dc:creator>marisa saunders</dc:creator>
      <pubDate>Thu, 12 Jan 2023 16:44:35 +0000</pubDate>
      <link>https://dev.to/marisa-saunders/how-to-update-react-state-on-nested-objects-that-are-serialized-in-rails-2040</link>
      <guid>https://dev.to/marisa-saunders/how-to-update-react-state-on-nested-objects-that-are-serialized-in-rails-2040</guid>
      <description>&lt;p&gt;&lt;strong&gt;Introduction&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;While working on my phase-4 project at Flatiron School I was confronted with the task of repeatedly having to update nested state. This was due to the fact that I was accessing data in different models through the use of serializers in Rails, as opposed to making get requests for each model. While this is beneficial in terms of how fast the website is, this created the obstacle of figuring out how to update nested state. As this is something I struggled with for a while and it took a while for this concept to click in my head, I thought I would share what I learned, in case someone else out there is struggling as well.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Project Concept&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Big Apple Runners is an application built for runners to find routes in NYC and write reviews on them to share with each other. It is a single page full-stack CRUD application with a Ruby / Ruby on Rails backend and a React / Javascript frontend.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Big Apple Runners Models&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;User&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Has many reviews&lt;/li&gt;
&lt;li&gt;Has many routes through reviews&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Route&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Has many reviews&lt;/li&gt;
&lt;li&gt;Has many users through reviews&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Review&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Belongs to route&lt;/li&gt;
&lt;li&gt;Belongs to user&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;What is state?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;State is a built-in React object that is used to contain data or information about the component. A component’s state can change over time. Whenever its state changes the component re-renders. This change in state can happen as a response to a user action or event, and these changes determine the behavior of the component and how it will render.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What are serializers?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;ActiveModel::Serializer provides a simplified way to customize how the JSON rendered by our controllers is structured. Active Model Serializer provides a convention-based approach to serializing our resources. Meaning that if we have a "Route" model, we can also have a "RouteSerializer" serializer and Rails will default to use our serializer if we simply call "render json: route" in our controller.&lt;/p&gt;

&lt;p&gt;Within the serializer we can use the built in Active Record macros "has_many" and "belongs_to" to tell Rails which model data we want to gain access to through the serializer. All we have to do is use the same macros in the serializers that we used to set up associations in our model files. Rails then automatically uses the appropriate serializer, based on naming conventions, to display the associated data for each of our models.&lt;/p&gt;

&lt;p&gt;From a front end perspective this is great because you don't have to make as many fetch requests, but the data you now have access to are nested objects in the data you are fetching from. This means you have to update the state of nested objects which takes a bit more work on your end.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How to:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In the app component I made a GET request to "/routes":  &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5ek9cfjhw6a8vk7ybwtc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5ek9cfjhw6a8vk7ybwtc.png" alt="Fetch Routes"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Instead of making a separate fetch request to "/reviews" to access the reviews data, I created a "RouteSerializer" that I told to access the "reviews" model&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8gq68bmedvevm92yrs7t.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8gq68bmedvevm92yrs7t.png" alt="Route Serializer"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next I updated nested state to have access to the object. It is important to note that because review data is accessed through "/routes" the state that needs to be updated is the route state. But in order to access reviews, which is nested we need to iterate twice, first through routes to get to reviews and then through reviews in order to access whatever is it is we are trying to change in reviews.  &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frzzwsvp74yz37rtirdll.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frzzwsvp74yz37rtirdll.png" alt="Delete Review"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4398cch6cqcf5it51ofc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4398cch6cqcf5it51ofc.png" alt="Add Review"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frjxysc2tmoaca44cvmfd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frjxysc2tmoaca44cvmfd.png" alt="Update Review"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I hope this was helpful if you are feeling stuck on how to update nested state. I'm sure there are other ways you can do so, but this was the way that worked and made more sense to me. &lt;/p&gt;

</description>
      <category>rails</category>
      <category>react</category>
      <category>ruby</category>
      <category>javascript</category>
    </item>
    <item>
      <title>How to make a full-stack CRUD app with React and a Ruby Sinatra API</title>
      <dc:creator>marisa saunders</dc:creator>
      <pubDate>Tue, 01 Nov 2022 18:45:47 +0000</pubDate>
      <link>https://dev.to/marisa-saunders/how-to-make-a-full-stack-crud-app-with-react-and-a-ruby-sinatra-api-29ed</link>
      <guid>https://dev.to/marisa-saunders/how-to-make-a-full-stack-crud-app-with-react-and-a-ruby-sinatra-api-29ed</guid>
      <description>&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What is Sinatra?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;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&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What is React?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What is CRUD?&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;CREATE, READ UPDATE, and DELETE are the database commands that make up the foundations of CRUD&lt;/p&gt;

&lt;p&gt;Routes used in my application: &lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Name&lt;/th&gt;
&lt;th&gt;Method&lt;/th&gt;
&lt;th&gt;Route&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Create&lt;/td&gt;
&lt;td&gt;POST&lt;/td&gt;
&lt;td&gt;/model&lt;/td&gt;
&lt;td&gt;Creates a new record&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Read&lt;/td&gt;
&lt;td&gt;GET&lt;/td&gt;
&lt;td&gt;/model&lt;/td&gt;
&lt;td&gt;Reads &amp;amp; retrieves data based on input parameters&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Update&lt;/td&gt;
&lt;td&gt;PUT/PATCH&lt;/td&gt;
&lt;td&gt;/model/:id&lt;/td&gt;
&lt;td&gt;Updates data without overwriting it&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Destroy&lt;/td&gt;
&lt;td&gt;DELETE&lt;/td&gt;
&lt;td&gt;/model/:id&lt;/td&gt;
&lt;td&gt;Removes data from the database&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;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".&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Back-End&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;First a file tour! &lt;/p&gt;

&lt;p&gt;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. &lt;/p&gt;

&lt;p&gt;&lt;u&gt;Gemfile:&lt;/u&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjn1tjxeni3jit4rytigd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjn1tjxeni3jit4rytigd.png" alt="Gemfile"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;u&gt;config.ru:&lt;/u&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fflt4z2xovn2d6p236760.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fflt4z2xovn2d6p236760.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;u&gt;environment.rb:&lt;/u&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3mma8p0ssqq9dizfj8zd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3mma8p0ssqq9dizfj8zd.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;u&gt;Rakefile:&lt;/u&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flhzhnkaay3n89czo2tah.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flhzhnkaay3n89czo2tah.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Corneal-new&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;To start my backend I used the &lt;a href="https://rubygems.org/gems/corneal-new" rel="noopener noreferrer"&gt;Corneal-new:&lt;/a&gt; gem that creates a Sinatra skeleton for you to easily build off of when coding your application. &lt;/p&gt;

&lt;p&gt;Install the &lt;a href="https://github.com/thebrianemory/corneal" rel="noopener noreferrer"&gt;gem&lt;/a&gt;, 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.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Database Migrations&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;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). &lt;/p&gt;

&lt;p&gt;migration files:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F52flnfa93m01mb8pvi14.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F52flnfa93m01mb8pvi14.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fofa18b10dof66x25gnf4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fofa18b10dof66x25gnf4.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Active Record Associations&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;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):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class Cat &amp;lt; ActiveRecord::Base
  has_many :listings
end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class Listing &amp;lt; ActiveRecord::Base
  belongs_to :cat
end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Controllers&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;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'.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Read (GET)&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;to view go to &lt;a href="http://127.0.0.1:9393/cats" rel="noopener noreferrer"&gt;http://127.0.0.1:9393/cats&lt;/a&gt; in your browser(when you run shotgun it will provide a url for you in the terminal)
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#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
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Read (GET)&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;to view go to &lt;a href="http://127.0.0.1:9393/:id" rel="noopener noreferrer"&gt;http://127.0.0.1:9393/:id&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;this route allows you to see an individual category based on the id you provide in the url
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;get '/cats/:id' do
  cat = Cat.find_by_id(params[:id])
  cat.to_json
end

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Creat(POST)&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;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
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;post "/cats" do
   cat = Cat.create(
     job_type: params[:job_type]
   )
   cat.to_json  
end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Update (PATCH)&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;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
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;patch '/dats/:id' do
 cat = Cat.find(params[:id])
 cat.update(
  job_type: params[:job_type]
 )
 cat.to_json)
end 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;DELETE&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;This route takes an id of a category to be deleted in the url and then deletes it using the .destroy method
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;delete '/cats/:id' do
   category = Cat.find(params[:id])
   category.destroy
end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;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&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhip0d9os4o5wv09h8ryl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhip0d9os4o5wv09h8ryl.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuf9u1ykgmocvp4p3otz1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuf9u1ykgmocvp4p3otz1.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Front-End&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;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. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Read(GET)&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;useEffect(() =&amp;gt; {
    fetch("http://localhost:9393/cats")
    .then((r) =&amp;gt; r.json())
    .then((data) =&amp;gt; {
      setCats(data);
    });
  }, []);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Create(POST)&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const configObj = {
   method: "POST",
   headers: {
     Accept: "application/json",
     "Content-Type": "application/json",
   },
    body: JSON.stringify({
     job_type: jobType
    }),
};

const handleSubmit = (e) =&amp;gt; {
    e.preventDefault();

    fetch("http://localhost:9393/cats", configObj)
      .then((r) =&amp;gt; r.json())
      .then((cat) =&amp;gt; {
        addNewCategory(cat);
      });
  };
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;*&lt;em&gt;Update(PATCH) *&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; function handleEditCategory(e) {
    e.preventDefault();

    fetch(`http://localhost:9393/cats/${id}`, {
    method: "PATCH",
    headers: { 
      'Content-Type': 'application/json',
    },
    body: JSON.stringify(formData),
   })
    .then ((response) =&amp;gt; response.json())
    .then((updatedCategory) =&amp;gt; {
      handleUpdateCategory(updatedCategory);
    });
  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;DELETE&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const handleDelete = () =&amp;gt; {
    fetch(`http://localhost:9393/cats/${id}`, {
      method: 'DELETE',
    });
    const updatedCats = cats.filter((cat) =&amp;gt; cat.id !== id);
    setCats(updatedCats);
  };
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Hopefully this tutorial has been helpful in guiding you on how to start building full-stack applications. Here's a link to the &lt;a href="https://github.com/marskimiko/job-board-front-end" rel="noopener noreferrer"&gt;front-end&lt;/a&gt; and &lt;a href="https://github.com/marskimiko/job-board-app" rel="noopener noreferrer"&gt;back-end&lt;/a&gt; GitHub repositories for my application. &lt;/p&gt;

</description>
      <category>ruby</category>
      <category>react</category>
      <category>sinatra</category>
      <category>api</category>
    </item>
    <item>
      <title>Understand the useEffect hook in react</title>
      <dc:creator>marisa saunders</dc:creator>
      <pubDate>Thu, 02 Jun 2022 19:01:16 +0000</pubDate>
      <link>https://dev.to/marisa-saunders/understand-the-useeffect-hook-in-react-45g9</link>
      <guid>https://dev.to/marisa-saunders/understand-the-useeffect-hook-in-react-45g9</guid>
      <description>&lt;p&gt;The useEffect hook in react  is one of the many hooks that you can use as a react developer. &lt;/p&gt;

&lt;p&gt;A good place to start would be of an explanation of what exactly "hooks" are: &lt;/p&gt;

&lt;p&gt;Hooks were introduced into React version 16.8 to solve the issue of developers often reusing the same code throughout different components as an alternate approach to classes. With hooks, instead of having complex components with stateful logic that cannot be reused, hooks introduced a way for developers to break up a component into smaller fragmented functions, based off of their functionality. &lt;/p&gt;

&lt;p&gt;As a new developer I had learned to use functions and hooks before classes in React, but I advise you to try to code the same functionality using classes to truly understand the advantages. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;With Hooks, you can extract stateful logic from a component so it can be tested independently and reused. Hooks allow you to reuse stateful logic without changing your component hierarchy. This makes it easy to share Hooks among many components or with the community - reactjs.org&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;The Effect Hook (useEffect)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Data fetching, subscriptions, and making manual changes to the DOM are all considered "side effects" meaning that they affect other components and cannot occur during rendering.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;An operation, function or expression is said to have a side effect if it modifies some state variable value(s) outside its local environment — Wikipedia on Side Effects&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The purpose of the useEffect hook was to introduce the ability to execute side effects from function components.&lt;/p&gt;

&lt;p&gt;Calling useEffect tells react to execute your effect after React has updated the DOM (after every render). Because effects are declared inside of the component they have access to the both the components props and state. &lt;/p&gt;

&lt;p&gt;In order to use the useEffect hook we first must import it from React.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React, { useEffect } from "react";
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After doing so you can then call useEffect from within your component, here's a basic example of how to use the hook:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React, { useEffect } from "react";

function ExampleUseEffect() {

  useEffect(() =&amp;gt; {
    console.log("you just called useEffect WOO!");
  });

console.log("Component rendering");

return (
    &amp;lt;div&amp;gt;
      &amp;lt;button &amp;gt;Click to call useEFfect&amp;lt;/button&amp;gt;
    &amp;lt;/div&amp;gt;
  );
};

export default ExampleUseEffect;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What order do you think the console messages appeared in? If you said "Component rendering" first and "you just called useEffect WOO!" second then you are correct! I am bringing this up to reinforce that useEffect is called AFTER rendering. By default, useEffect will run side effect functions every time the component re-renders: &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;render -&amp;gt; useEffect -&amp;gt; setState -&amp;gt; re-render -&amp;gt; useEffect&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In the event that we don't want to make a network request every time our component is updated, and instead only the first time our component renders, we can tell react to only run our side effect in certain conditions. &lt;/p&gt;

&lt;p&gt;Running the following code will result in an infinite loop of fetch requests which is most likely something we don't want to occur.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function MusicProjects() {
  const [musics, setMusics] = useState([]);
  const [count, setCount] = useState(0);

  useEffect(() =&amp;gt; {
    fetch("http://localhost:3004/music/")
      .then((r) =&amp;gt; r.json())
      .then((data) =&amp;gt; {
        // setting state in the useEffect callback
        setMusics(data.message);
      });
  });

  return (
    &amp;lt;div&amp;gt;
      {musics.map((music) =&amp;gt; (
        &amp;lt;img src={music} key={music} /&amp;gt;
      ))}
    &amp;lt;/div&amp;gt;
   &amp;lt;button onClick={() =&amp;gt; setCount((count) =&amp;gt; count + 1)}&amp;gt;
        I've been clicked {count} times
   &amp;lt;/button&amp;gt;
  );
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In order to mitigate when the side effect runs we can pass a second argument to useEffect known as a dependencies array. Passing a variable in the array will cause the side effect to run only when said variable changes, while passing an empty array as the second argument will cause the side effect to run only the first time that the component renders, solving the issue of the infinite loop in the previous example. &lt;/p&gt;

&lt;p&gt;useEffect with a variable in the array (side effect will run only when the count variable changes):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;useEffect(() =&amp;gt; {
    fetch("http://localhost:3004/music/")
      .then((r) =&amp;gt; r.json())
      .then((data) =&amp;gt; {
        // setting state in the useEffect callback
        setMusics(data.message);
      });
  }, [count]);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Empty dependencies array (side effect will run only the first time our component renders):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;useEffect(() =&amp;gt; {
    fetch("http://localhost:3004/music/")
      .then((r) =&amp;gt; r.json())
      .then((data) =&amp;gt; {
        // setting state in the useEffect callback
        setMusics(data.message);
      });
  }, []);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You also have the ability to pass multiple variables into the dependencies array that will run whenever either of the variables change:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;useEffect(() =&amp;gt; {}, [variable1, variable2])
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;• useEffect is one of the many hooks available in React&lt;/p&gt;

&lt;p&gt;• useEffect is used to trigger side effects&lt;/p&gt;

&lt;p&gt;• Dependencies arrays can but used to specify when the side effect will run&lt;/p&gt;

&lt;p&gt;• An empty dependencies array will tell useEffect to run only the first time our component renders &lt;/p&gt;

</description>
      <category>react</category>
      <category>webdev</category>
      <category>beginners</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Fetch Requests Taught Me the Importance Of console.log()</title>
      <dc:creator>marisa saunders</dc:creator>
      <pubDate>Tue, 08 Mar 2022 19:22:22 +0000</pubDate>
      <link>https://dev.to/marisa-saunders/fetch-requests-taught-me-the-importance-of-consolelog-351m</link>
      <guid>https://dev.to/marisa-saunders/fetch-requests-taught-me-the-importance-of-consolelog-351m</guid>
      <description>&lt;p&gt;&lt;strong&gt;Introduction&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I am new to coding and I think one of the most important lessons I have learned so far, is that in order for me to truly learn and understand what I am coding, I need to physically see what my code is doing in the background. &lt;/p&gt;

&lt;p&gt;Initially, I was just typing out what I thought was right in Visual Studio Code. I was running the tests, seeing them fail, and just trying to edit my code over and over until the tests finally passed. This meant I was coding without actually digging into why my code was wrong and checking what it was that my failing code was actually doing in the background. &lt;/p&gt;

&lt;p&gt;So now, I am constantly placing console.log(s) throughout my code, and seeing what pops up in the console in dev tools. I also downloaded the Live Server extension so I can get immediate feedback. &lt;/p&gt;

&lt;p&gt;I'm basically going on this rant because the reason I discovered that I needed this was through fetch requests. Even though I understood fetch requests, I could not wrap my head around how to get the data I was fetching to appear on the page. And the first thing that really helped me to understand this was to console.log() my fetch and see that data in the console, and then get it to appear on the page, and that is when it really clicked.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Background:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I think should probably explain what a fetch request is for the sake of this blog, so here you go:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: I recently was working on a project where I used the Studio Ghibli API to display a list of Studio Ghibli films in the browser, so I will be using references from this project.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The fetch() function in Javascript is used to make a request to the server to retrieve data and display that data in the browser. &lt;/p&gt;

&lt;p&gt;It's a global method on the window object. That means you can use it simply by calling fetch() and passing in a path to a resource as an argument. The request can be used on any API that returns the data in either JSON or XML format. &lt;/p&gt;

&lt;p&gt;When using a fetch request you only need one parameter, as opposed to other requests, because fetch defaults to send an HTTP &lt;strong&gt;GET&lt;/strong&gt; request. Fetch instantaneously returns a promise object. The three promise object statuses are pending, fulfilled, and rejected. To use the data that is returned by the fetch(), and see it in the browser, we need to chain on the then() method which will keep fetching until the status of the request is "fulfilled". We can see what this looks like below:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function getFilms() {
fetch('https://ghibliapi.herokuapp.com/films')
  .then(res =&amp;gt; res.json())
  .then(data =&amp;gt; {
    console.log(data);
  })
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice the console log! If you are coding along open up your file in the browser, open up dev tools, and take a look at what is being logged to the console. It's an array of 22 objects! For me seeing this is so satisfying. It's telling me I am doing the right thing, I am on right the path, and I actually know what I am doing. I think this is so important, especially when you are learning something new at a quick pace as a means to stop self doubt from taking over. &lt;/p&gt;

&lt;p&gt;Here's what that data looks like in the console:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F93odhb82iaj3x0umhyob.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F93odhb82iaj3x0umhyob.png" alt="Image description" width="800" height="776"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 2:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Ok great! So now that we have seen our data, we need to get our data on the page. In order to do this we need to decide where we want to attach our data to. For this project I had an ul in my index.html file (here's a snippet of that code for reference)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; &amp;lt;div id="main"&amp;gt;
      &amp;lt;ul id="film-list"&amp;gt;&amp;lt;/ul&amp;gt;
      &amp;lt;div id="info"&amp;gt;&amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and decided I would attach the films to the ul in order to have them display in the browser. But, in order to put them in the unordered list I need to create li's, iterate over the li's to attach each object in the array to, and ultimately display them in the browser.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function getFilms() {
  const ul = document.getElementById('film-list')
  fetch('https://ghibliapi.herokuapp.com/films')
  .then(res =&amp;gt; res.json())
  .then(data =&amp;gt; {
    data.forEach(film =&amp;gt; {
      ul.innerHTML += `
      &amp;lt;li&amp;gt;${film.title}&amp;lt;/li&amp;gt;
      `
    })
  })
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here's how they show up in the browser: &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9y3u5x420yipykv5t86g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9y3u5x420yipykv5t86g.png" alt="Image description" width="634" height="1030"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I'm sharing this because for whatever reason it took so long for me to realize how important something as simple as a console.log() is in regards to your learning. It can guide you on how and what to google if you're stuck while coding. Stick them throughout your code! I think its better that you have too many than not enough, and see if this helps show you more about what your code is doing than you understood before. &lt;/p&gt;

</description>
      <category>javascript</category>
      <category>beginners</category>
      <category>webdev</category>
      <category>programming</category>
    </item>
    <item>
      <title>Why I signed up for a software engineering bootcamp</title>
      <dc:creator>marisa saunders</dc:creator>
      <pubDate>Tue, 08 Mar 2022 02:42:07 +0000</pubDate>
      <link>https://dev.to/marisa-saunders/why-i-signed-up-for-a-software-engineering-bootcamp-2j5b</link>
      <guid>https://dev.to/marisa-saunders/why-i-signed-up-for-a-software-engineering-bootcamp-2j5b</guid>
      <description>&lt;p&gt;I think this pandemic has done a really good job at revealing what actually matters to me. It's introduced a level of unpredictability that I hadn't imagined prior, and ultimately I'm tired tired and have been craving stability. I want to be free to travel and work from anywhere in the world without feeling tied to one place. I also want to push and challenge my brain to work in ways it hasn't necessarily worked in before. &lt;/p&gt;

&lt;p&gt;For the last few years I've been working freelance as an Audio Engineer. This has included working at various recording studios, assisting for engineers, mastering, and mixing. I also produce my own music as well as DJ. This is my passion, it's what I love, but the money isn't great and I've found that turning music into work has taken away from the love and energy that I feel able to direct towards it. I want music to always feel like a choice and not an obligation. &lt;/p&gt;

&lt;p&gt;Last October, I was talking about how tired I am of being broke while on a trip to Mexico City with some friends, and jokingly brought up that I should just learn how to code. But just like most things in my life, the second I have a small idea about something, I cant help but really dig into it. Right upon getting back to New York, I immediately decided to do a Codecademy course to see if I this was something I could get into and within 2 weeks of the course I started apply to bootcamps. I honestly just trusted my gut. I was having fun on Codecademy and just wanted to keep digging deeper into what I was learning and ultimately knew that I would need the pressure and structure of a bootcamp to truly succeed. &lt;/p&gt;

&lt;p&gt;So far it has been going really well. I'm having a lot of fun. It's been hard but I'm enjoying the challenge and really looking forward to the future and what life could be once I start my new career.&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
