DEV Community

JosetteTGarcia
JosetteTGarcia

Posted on

Troubleshooting API through Binding.Pry

This week, I completed another phase and project through Flatiron School’s Software Engineering program. In this phase, we’ve focused on building the backend of applications through Ruby, Active Record, and Sinatra.

My project focussed on payment tracking to assist users with saving. To track and categorize payments, I had two, one-to-many model associations:

  • Payments belong to Stores
    • Stores have many payments
  • Payments belong to Categories
    • Categories have many payments

Setting up the migrations, models, and controllers came without issue. What did not make sense right away was how to build a Payment, with the above relationships, when a user submits payment information through a form.

I struggled for a full 48 hours to understand how to format my Payment object through Javascript that correctly POSTs to the Sinatra built API and identify the two foreign keys I needed connected.

This blog will cover how I accomplished this task and how Binding.Pry helped me find a solution when I was stuck.

To start, I will explain my API, Frontend Requests, and the Submission Form for Payments:

The Set Up

As described, a Payment belongs to a Store and Category. Categories & Stores can have many payments. Categories and Stores do not currently tie together.

Here is the Payment database model:

Image description

A user can submit a payment through the following React form:

Image description

Form Submission to POST was something I had encountered before, but relating a value to a foreign key, when the user will have no concept of the foreign key's ID truly knocked me down.

Tip #1: The JS object, or 'Form Data', as I've called it must include the required key, value pairs the server is expecting on the backend.
This may sound obvious, but as I was expecting a user to input a category or store name, I had assumed the client would send the category/store names and then store_id and category_id would be converted server side. This is not the case in my example!

const [formData, setFormData] = useState({
      amount: "",
      date_paid: "",
      description: "",
      is_need: false,
      store_id: "",
      category_id: "",
  })
Enter fullscreen mode Exit fullscreen mode
  const categoriesList = categories.map((category) => (
    <MenuItem key={category.id} value={category.id}>{category.category_type}</MenuItem>
  ))

 <Select
          displayEmpty
          id="standard-basic"
          className={classes.selectEmpty}
          name="category_id"
          value={formData.category_id}
          onChange={handleChange}
          inputProps={{ 'aria-label': 'Without label' }}
          > 
          <MenuItem value="" disabled>
                Category
          </MenuItem>
          {categoriesList}
        </Select> 
Enter fullscreen mode Exit fullscreen mode

In my case, I chose to use a Select element for category and store submission to make it easier for the user and myself. The Categories display as MenuItems and that also gives me a chance to store that specific category's id under name="category_id".

When a store or category is selected, JS then does the work of inserting the corresponding ID to our FormData.

function handleChange(event) {
    if(event.target.name === "amount"){
      setFormData({
        ...formData,
          amount: parseFloat(event.target.value)
      }) 
    }
      else {
        setFormData({ 
          ...formData, 
          [event.target.name]: event.target.value 
        });
      }
  }
Enter fullscreen mode Exit fullscreen mode

The Server Side

Where I started to see smoke as a newbie engineer is that my JS object was showing up perfectly in the console.log output. But I was receiving specific API errors that Payment could not be submitting because the params were empty.

aka. My beautiful work was not coming across correctly in the server.

Tip #2: Use Binding.Pry AND Play With It.

Here was my initial payments_controller for a POST:

Image description

and here is what binding.pry was providing me when I peeked into Payment:

Image description

Nil!? How could that be when my object looked great before it was sent to server?

A tip from an instructor led me to try viewing the [params :payment] vs. just (params) within IRB. This led me to see that I was submitting data correctly, but I was asking my server to look for params called "payment", which did not exist as a key, value pair in my object. The solution:

post "/payments" do
    payment = Payment.new(params)
    if payment.save
      payment.to_json(include: [:store, :category])
    else
      {errors: payment.errors.full_messages}.to_json
    end
  end
Enter fullscreen mode Exit fullscreen mode

Back tracking to just asking for "params" solved my issue (+/- some other tweaks to my code)! How could something so small trip me up for two days?

To put it simply, I was looking for the most complicated reason when binding.pry could have led me to a simple fix much quicker.

Conclusion:

I still struggled with the rest of my API calls because I was just getting used to Sinatra and Active Record set up. Leaning on binding.pry on the server side while also still utilizing console.log on the client end helped make sure the data was matching on both ends, taking less of my time!

Thanks for reading!

Top comments (0)