React App error PATCH http://localhost:4000/items/undefined - reactjs

I am getting this error trying to update a card for my application. Here's a look at the rails server log. The ID is coming back "nil". I can't figure out why. Here is the PATCH update block of code:
function handleEdit(e) {
e.preventDefault()
fetch(`/items/${item.id}`,{
method: "PATCH",
body: JSON.stringify({
item: id,
bottle: bottle,
size: size,
count: count,
}),
headers: {
"Content-Type": "application/json",
},
})
.then(res=>res.json())
.then((updatedItem)=>setItem(updatedItem))
}
Here are all the routes:
resources :items, only: [:index,:show,:update]
get '/me', to: 'couriers#show'
get "/home", to: 'couriers#show'
get '/courier', to: 'couriers#show'
get '/items', to: 'items#index'
get 'items/:id', to: 'items#update'
get '/items/:id', to: 'items#show'
patch '/items/:id', to: 'items#update'
post '/login', to: 'sessions#create'
post '/signupform', to: 'couriers#create'
delete '/logout', to: 'sessions#destroy'
Here is the error log:
Started PATCH "/items/undefined" for 127.0.0.1 at 2022-08-01 19:27:47 -0400
Processing by ItemsController#update as */*
Parameters: {"item"=>nil, "bottle"=>"Glass", "size"=>"400", "count"=>"4", "id"=>"undefined"}
Item Load (0.2ms) SELECT "items".* FROM "items" WHERE "items"."id" = $1 LIMIT $2 [["id", nil], ["LIMIT", 1]]
↳ app/controllers/items_controller.rb:19:in `update'
Completed 404 Not Found in 4ms (Views: 0.2ms | ActiveRecord: 0.9ms | Allocations: 1234)
Here is the code in the ItemsController:
class ItemsController < ApplicationController
skip_before_action :authorize, except: :index
def index
items = Item.all
render json: items, status: :ok
end
def show
item=Item.find_by(id:session[:id])
if item
render json: item
else
render json: {error: 'Not Found'}, status: :not_found
end
end
def update
item = Item.find_by(id:params[:id])
if item
item.update(item_params)
render json: item
else
render json: { error: "Item not found" }, status: :not_found
end
end
private
def item_params
params.permit(:id,:item,:bottle, :size, :count)
end
end
If anyone has an idea or resolution, please share. I'm sure it's something I may be doing wrong, so anything helps.

Not super sure how React apps work, but should that ${items.id} in the patch code be ${item.id} (singular)?
Out of curiosity, where is the item (or items) var actually set? Again, I'm not familiar with React, but that's the source of the 'undefined' text being passed to the controller. Whatever is rendered in the ${ } section is undefined. It is being turned into the literal text 'undefined' and that is being sent to your controller.

Related

Rails - POST request: Error 500 (Internal Server Error)

I'm a beginner coder and I'm trying to create an application using React as my front end and Ruby on Rails for my back end. Anytime I press the sign up button and send the request to server I'm receiving an error and I cannot figure out what it is. Help!
Console:
SignUp.js:17
POST http://localhost:4000/users 500 (Internal Server Error)
SignUp.js:26
Response {type: 'basic', url: 'http://localhost:4000/users', redirected: false, status: 500, ok: false, …} body: (...) body Used: true headers: Headers {} ok: false redirected: false status: 500 statusText: "Internal Server Error" type: "basic" url: "http://localhost:4000/users" [[Prototype]]: Response
When trying to access localhost
GET http://localhost:3000/me 500 (Internal Server Error)
favicon.ico:1 GET http://localhost:3000/favicon.ico 500 (Internal Server Error)
Rails Server:
ArgumentError (wrong number of arguments (given 0, expected 1..2)):
app/controllers/users_controller.rb:2:in `<class:UsersController>'
app/controllers/users_controller.rb:1:in `<main>'
Started POST "/users" for 127.0.0.1 at 2022-11-02 23:09:07 -0400
ArgumentError (wrong number of arguments (given 0, expected 1..2)):
app/controllers/users_controller.rb:2:in `<class:UsersController>'
app/controllers/users_controller.rb:1:in `<main>'
React front end
import React from 'react';
import { useState } from "react";
function SignUp() {
const [username, setUsername] = useState("");
const [password, setPassword] = useState("");
function handleSignUp(e) {
e.preventDefault()
const user = {
username,
password
}
fetch("/users",{
method: "POST",
header: {
"Content-Type" : "application/json"
},
body: JSON.stringify(user)
}).then(r => {
r.json()
console.log(r)})
}
return (
<div>
<form onSubmit={handleSignUp}>
<p>Username</p>
<input
type="text"
value={username}
onChange={(e) => setUsername(e.target.value)}
/>
<p>Password</p>
<input
type="text"
value={password}
onChange={(e) => setPassword(e.target.value)}
/>
<button type="submit">Sign Up</button>
</form>
</div>
);
}
export default SignUp;
Routes
Rails.application.routes.draw do
# Routing logic: fallback requests for React Router.
# Leave this here to help deploy your app later!
post "/login", to: "sessions#create"
delete "logout", to: "sessions#destroy"
get "/me", to: "users#show"
post "/users", to: "users#create"
get "*path", to: "fallback#index", constraints: ->(req) { !req.xhr? && req.format.html? }
end
Controller
class UsersController < ApplicationController
wrap_parameters
rescue_from ActiveRecord:RecordInvalid, with: :record_invalid_response
def create
user = User.create!(user_params)
render json: user, status: :created
rescue ActiveRecord::RecordInvalid => invalid
end
def show
user = User.find(session[:user_id])
if user
render json: user
else
render json: { error: "Not authorized" }, status: :unauthorized
end
end
private
def user_params
params.permit(:username, :password)
# :first_name, :last_name, :phone_number, :email
end
def record_invalid_response(user)
render json: {error: user.errors.full_messages}, status: :unprocessable_entity
end
end
:The error comes from the fact that wrap_parameters expects some arguments, see https://api.rubyonrails.org/classes/ActionController/ParamsWrapper.html.
Now, for a JSON request, you don't need to call this function as Rails does it by default. But then I suppose Rails wraps your params with a user key and so you need to change your params processing, something like this should work:
class UsersController < ApplicationController
rescue_from ActiveRecord::RecordInvalid, with: :record_invalid_response
def create
user = User.create!(user_params)
render json: user, status: :created
end
def show
user = User.find(session[:user_id])
if user
render json: user
else
render json: { error: "Not authorized" }, status: :unauthorized
end
end
private
def user_params
params.require(:user).permit(:username, :password)
# :first_name, :last_name, :phone_number, :email
end
def record_invalid_response(user)
render json: {error: user.errors.full_messages}, status: :unprocessable_entity
end
end
Note: I also removed the rescue from the create action as it would prevent your controller-level rescue_from from being used

Rails/React App Signup throwing 500 internal server error

I'm trying to get user data to save to my Rails DB for user info through a sign up form on a React front end. I've got my route and controller written properly (at least I think) and the fetch request below but I keep getting a 500 internal error through on submit. Please let me know what I'm missing, any help would be greatly appreciated!
My route:
resources :users, only: [:show, :create]
My create action in UsersController:
def create
user = User.create!(user_params)
if user.valid?
session[:user_id] = user.id # remembering who our user is
render json: user, status: :ok
else
render json: {error: user.errors.messages}
end
end
and lastly my fetch request from the Signup.js component on the React frontend, where I'm getting the error on the line that has 'fetch'
fetch(`/users`,{
method:'POST',
headers:{'Content-Type': 'application/json'},
body:JSON.stringify(user)
})
.then(res => {
if(res.ok){
res.json().then(user => {
history.push(`/users/${user.id}`)
})
This might only be part of your problem, but first creating, then asking for validity is backwards.
Do something like this instead:
def create
user = User.new(user_params)
if user.save # <-- will return false if the save fails
user.reload
session[:user_id] = user.id # remembering who our user is
render json: user, status: :ok
else
render json: {error: user.errors.messages}
end
end
If you really want to check validity explicitly:
def create
user = User.new(user_params)
if user.valid? # <-- will check validity
user.save
user.reload
session[:user_id] = user.id # remembering who our user is
render json: user, status: :ok
else
render json: {error: user.errors.messages}
end
end
My guess is your error might be coming from the fact that your user variable doesn't actually have an ID yet. You need to save the record, then refresh it to get an ID.

Sending data properly from React to Ruby on Rails API Endpoint

I'm working on posting data from a React Form to a Ruby on Rails API, about the React part, if just send the first item from an array using this code:
const submitOrderHandler = async (userData) => {
setIsSubmitting(true);
await fetch("http://localhost:3000/ordertemps", {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(cartCtx.items[0]),//please include user: userData
});
setIsSubmitting(false);
setDidSubmit(true);
cartCtx.clearCart();
};
The Ruby on Rails API manage it and store it in the table, this is the output:
However, I need to store all the data selected by the user, so, to accomplish this task I updated my code like this:
const submitOrderHandler = async (userData) => {
const dataSelected = JSON.stringify(cartCtx.items);
console.log(dataSelected);
setIsSubmitting(true);
await fetch("http://localhost:3000/ordertemps", {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(cartCtx.items),//please include user: userData
});
setIsSubmitting(false);
setDidSubmit(true);
cartCtx.clearCart();
};
The problem is I'm getting a 400 Status, so this is how the data looks from the FrontEnd:
This is the output from the Ruby on Rails Endpoint:
the source code of the Controller in charge to manage and store the data is this:
#POST /ordertemps
def create
#ordertemp = Ordertemp.new(ordertemp_params)
if #ordertemp.save
render json: #ordertemp
else
render error: { error: 'Unable to create an order'}, status: 400
end
end
private
def ordertemp_params
#params.require(:ordertemp).permit( :clientName, :clientId, :amount, :mealid, :name, :price)
params.require(:ordertemp).permit(:name, :amount, :price)
end
So, I'm assuming these facts:
the data is properly formatted from the FrontEnd.
For some reason my Ruby on Rails'Controller can't manage more than one element sent by the front end.
My question is: what am I missing in my controller to store all the data sent by the FrontEnd?
Thanks a lot for your comments
Update your controller code as below:
#POST /ordertemps
def create
begin
params['_json'].each do |ordertemp_params|
#ordertemp = Ordertemp.new(ordertemp_params)
#ordertemp.save
end
head :no_content
rescue => e
render json: { error: unable to create orders }, status: 400
end
end
Hope this will help you.

HTTP 400 error: formatting properly a JSON request using React

I'm working on a POST request from React to Ruby on Rails backend; I tested the endpoint using Postman with the bellow data in JSON format:
{
"amount": 2,
"name": "Cheese and Loroco",
"price": "1.55"
}
And it worked(status 200); now, from React my JSON request looks like this:
{"ordertemp":[{"name":"Cheese and Loroco","amount":1,"price":"1.25"}]}
And I'm obtaining a status 400.
So the code that I'm using to generate the request is the bellow:
await fetch("http://localhost:3000/ordertemps", {
method: 'POST',
BODY: JSON.stringify({
//user: userData,
ordertemp: cartCtx.items,
}),
});
About my backend, I'm obtaining this otuput:
My controller sourcecode looks like this:
class OrdertempsController < ApplicationController
#GET /ordertemps
def index
#ordertemps = Ordertemp.all
render json: #ordertemps
end
#GET /ordertemp/:id
def show
#ordertemp = Ordertemp.find(params[:id])
render json: #ordertemp
end
#POST /ordertemps
def create
#ordertemp = Ordertemp.new(ordertemp_params)
if #ordertemp.save
render json: #ordertemp
else
render error: { error: 'Unable to create an order'}, status: 400
end
end
#PUT /ordertemps/:id
def update
#ordertemp = Ordertemp.find(params[:id])
if #ordertemp
#ordertemp.update(ordertemp_params)
render json: { message: 'Order successfully updated.'}, status: 200
else
render json: { error: 'Unable to update the order.', status: 400}
end
end
#DELETE /ordertemps/:id
def destroy
#ordertemp = Ordertemp.find(params[:id])
if #ordertemp
#ordertemp.destroy
render json: { message: 'Order successfully deleted.'}, status: 200
else
render json: { error: 'Unable to delete Order.'}, status: 400
end
end
private
def ordertemp_params
#params.require(:ordertemp).permit( :clientName, :clientId, :amount, :mealid, :name, :price)
params.require(:ordertemp).permit(:amount, :name, :price)
end
end
So, I would like to request your help with the next questions:
should I get rid off the "ordertemp" at the beginning of my JSON from React? in the case yes, how can I accomplish it?
what else am I forgetting to get a status 200 instead of 400?
Thanks a lot
I don't do ruby, but with postman you are sending this
{
"amount": 2,
"name": "Cheese and Loroco",
"price": "1.55"
}
whereas on react you are sending this:
{"ordertemp":[{"name":"Cheese and Loroco","amount":1,"price":"1.25"}]}
They are not the same, so start with the same use case and see if it works.
Also, BODY should be body and you could add headers like in the fetch example
I noticed in your controler that Ordertemp is the a capitalized letter (I don't know if it matters)

How to post data to a local route using fetch in flask/react.js?

I am trying to send the contents of a flashcard to a backend route http://127.0.0.1:5000/post onClick and it works when I send the data to webhook.site but when I change it to http://127.0.0.1:5000/post I get the error " question = data['question' TypeError: 'NoneType' object is not subscriptable ". Here is the code for the fetch request:
async function postData() {
try {
let result = await fetch('http://127.0.0.1:5000/post', {
method: 'POST',
mode: 'no-cors',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
key: `${Date.now()}`,
question: flashcard.question,
answer: flashcard.answer,
options: flashcard.options
})
});
} catch(e) {
console.log(e)
}
}
and here is the code for the backend route in flask:
#app.route('/post', methods=['GET', 'POST'])
def post():
#save data to db
data = request.get_json()
question = data['question']
answer = data['answer']
options = data['options']
key = data['key']
return jsonify({'question' : question, 'answer' : answer, 'options' : options, 'key' : key})
if __name__ == "__main__":
app.run(debug=True)
I get that the error is stating that "data" has no value which I assume means it's not recieving the JSON objects that I'm posting. It's weird because it works perfectly when I use a webhook.site url. can anyone help? thanks for your time!
Seems like your content is not a valid json request. If that is the case then content will be equal to None(not subscriptable).
Try to debug how data looks in flask and based on that you will know if its valid json.

Resources