Home > Net >  Why do I get a Routing error when I do a PATCH request on rails backend?
Why do I get a Routing error when I do a PATCH request on rails backend?

Time:09-01

Hi I have a React frontend and Rails backend. And something very weird is happening when I do. PATCH request on the backend. I get some routing error in my rails log.No idea why this is happening pls help me out.... heres my code Here is the error

Started PATCH "/reservation/2" for 127.0.0.1 at 2022-09-01 00:32:51  0530
  
ActionController::RoutingError (No route matches [PATCH] "/reservation/2"):
  
Started GET "/me" for 127.0.0.1 at 2022-09-01 00:32:51  0530
Processing by UsersController#show as */*
hello
4
  User Load (0.3ms)  SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT $2  [["id", 4], ["LIMIT", 1]]
  ↳ app/controllers/application_controller.rb:9:in `authorize'
[active_model_serializers] Rendered UserSerializer with ActiveModelSerializers::Adapter::Attributes (0.17ms)
Completed 200 OK in 2ms (Views: 0.4ms | ActiveRecord: 0.3ms | Allocations: 832)


Started GET "/reservations" for 127.0.0.1 at 2022-09-01 00:32:51  0530
Processing by ReservationsController#index as */*
hello
4
  User Load (0.2ms)  SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT $2  [["id", 4], ["LIMIT", 1]]
  ↳ app/controllers/application_controller.rb:9:in `authorize'
  Reservation Load (0.2ms)  SELECT "reservations".* FROM "reservations" WHERE "reservations"."user_id" = $1  [["user_id", 4]]
  ↳ app/controllers/reservations_controller.rb:4:in `index'
[active_model_serializers]   Restaurant Load (0.1ms)  SELECT "restaurants".* FROM "restaurants" WHERE "restaurants"."id" = $1 LIMIT $2  [["id", 30], ["LIMIT", 1]]
[active_model_serializers]   ↳ app/controllers/reservations_controller.rb:4:in `index'
[active_model_serializers] Rendered ActiveModel::Serializer::CollectionSerializer with ActiveModelSerializers::Adapter::Attributes (1.53ms)
Completed 200 OK in 4ms (Views: 2.3ms | ActiveRecord: 0.5ms | Allocations: 2873)

Routes.rb

Rails.application.routes.draw do
  
  resources :reservations,only: [:index,:show,:create,:update,:destroy]
  resources :reviews,only: [:index,:create,:destroy]
  resources :restaurants,only: [:index]
 

  
  post "/signup", to: "users#create"
  get "/me", to: "users#show"
  post "/login", to: "sessions#create"
  delete "/logout", to: "sessions#destroy"
  
end

The controller

 def update
        reservation = Reservation.find_by(id: params[:id])
        reservation.update!(reservation_params)
        render json: reservation,status: :ok

    end
  
   def reservation_params
        params.permit(:name, :date, :time, :num, :contact, :occasion,:user_id,:restaurant_id)

    end

and the front end App.js

function App() {
  const [user, setUser] = useState(null);
  
  const[reviews,setReviews]=useState([]);
  const[current,setCurrent]=useState({});
  useEffect(() => {
    document.title = "Nyc";
  }, []);

  useEffect(() => {
    // auto-login
    fetch("/me", { credentials: "same-origin" }).then((r) => {
      if (r.ok) {
        r.json().then((user) => setUser(user));
      }
    });
  }, [setUser]);
  function handleAddReviews(newReview) {
    setReviews([...reviews, newReview]);
  }

  
  if (!user) return <Loggin error={'please login'} onLogin={setUser} />;
  return (
    <Cont.Provider value={ {current,setCurrent}}>
    <div className="App">
   <Navbar user={user} setUser={setUser} />
   <Routes>
    <Route exact path="/blogs" element={<Blogs />} />
    
    <Route exact path="/myreservations" element={<MyReservations user={user} />} />

    <Route exact path="/restaurants/:id" element= {<RestaurantInfo handleAddReviews={handleAddReviews} user={user} reviews={reviews} setReviews={setReviews}/>}  />

    <Route exact path="/restaurants" element={<Restaurants />} />

     <Route exact path="/about" element={<About user={user} />} />

   </Routes>
   
   
    </div>
    </Cont.Provider>
  );
}

MyReservations.js

import {useEffect, useState } from "react";
import ReservationCard from "./ReservationCard";


function MyReservations({user}){
  // const[editMode,setEditForm]=useState(false);
  const[reservations,setReservations]=useState([]);
  useEffect(()=>{
    fetch("/reservations")
    .then(res=>res.json())
    .then(reservationData=>{
      setReservations(reservationData)
    })
  
   },[])
  
      // console.log("reservations",reservations)
      function handleUpdateReservation(updatedReservation) {
        const updatedReservations = reservations.map((reservation) => {
          if (reservation.id === updatedReservation.id) {
            return updatedReservation;
          } else {
            return reservation;
          }
        });
        setReservations(updatedReservations);
      }
    

      function handleCancel(reservationtodelete){
        const newReservations=reservations.filter(r=>r.id !== reservationtodelete)
         setReservations(newReservations)
         
       }
//  const renderReservations=reservations.map((reservation)=>(
//   <ReservationCard key={reservation.id} reservation={reservation} handleCancel={handleCancel}  />
//  ))

const renderReservations=reservations.map((reservation)=>(
  <ReservationCard key={reservation.id} reservation={reservation} handleCancel={handleCancel}  onUpdateReservation={handleUpdateReservation}  />
  ))
  
    return(
        <> 
        {renderReservations}
        </>
    )
}
export default MyReservations;

ReservationCard.js

function ReservationCard({reservation,handleCancel,onUpdateReservation}){
 
 
  const{ name, date, time, num, contact, occasion}=reservation;
  const [isEditing, setIsEditing] = useState(false);
  const handleReservationUpdate = (updatedReservation) => {
    setIsEditing(false);
    onUpdateReservation(updatedReservation);
  };

  function handleDeleteClick() {
    fetch(`/reservations/${reservation.id}`, {
     method: "DELETE",
       })
     handleCancel(reservation.id)
  }

  
    return(
        <>
        {isEditing ?( <EditReservationForm reservation={reservation}  onUpdateReservation={handleReservationUpdate} />) :(
           <div>
           <h2>{name}</h2>
           <h2>{date}</h2>
           <h2>{time}</h2>
           <h2>{num}</h2>
           <h2>{contact}</h2>
           <h2>{occasion}</h2>
           <h3>For-{reservation.restaurant.name}</h3>
           <button onClick={() => setIsEditing((isEditing) => !isEditing)}>
              Edit
            </button>
            <button onClick={handleDeleteClick}>Cancel Booking</button>
           </div>

        )}
       
       
      </>
    )
}
export default ReservationCard;

EditReservationForm

function EditReservationForm({reservation,onUpdateReservation}){
    const{ name, date, time, num, contact, occasion}=reservation;
    const[updateName,setUpdatedName]=useState(name);
   const[updateDate,setUpdatedDate]=useState(date);
   const[updateTime,setUpdatedTime]=useState(time);
   const[updateNum,setUpdatedNum]=useState(num);
   const[updateContact,setUpdatedContact]=useState(contact);
   const[updateOccasion,setUpdatedOccasion]=useState(occasion);

   function handleEditClick() {
      
  
            fetch(`/reservation/${reservation.id}`, {
              method: "PATCH",
            headers: {
                "Content-Type": "application/json",
              },
            body: JSON.stringify({ name:updateName,date:updateDate, time:updateTime,num:updateNum,contact:updateContact,occasion:updateOccasion}),
             })
               .then((r) => r.json())
              .then((updatedReservation) => {
                 onUpdateReservation(updatedReservation);
              });
       }
    return(
        <>
       <h2>Modify Reservation</h2>
       <form onSubmit={handleEditClick}  >
        <div >
        <label htmlFor="name"  >Name</label>
         <input type="text" name="name"  value={updateName}    onChange={(e) => setUpdatedName(e.target.value)} placeholder="name" />
       </div>
       <div >
        <label htmlFor="date"  >Date</label>
         <input type="date" name="date"   value={updateDate}  onChange={(e) => setUpdatedDate(e.target.value)}  placeholder="date" />
       </div>
       <div >
        <label htmlFor="time"  >Time</label>
         <input type="time" name="time"  value={updateTime}  onChange={(e) => setUpdatedTime(e.target.value)} placeholder="time" />
       </div>
       <div >
        <label htmlFor="num"  >Num</label>
         <input type="number" name="num"  value={updateNum}  onChange={(e) => setUpdatedNum(e.target.value)}  placeholder="num" />
       </div>
       <div >
        <label htmlFor="date"  >Contact</label>
         <input type="tel" name="contact" value={updateContact}  onChange={(e) => setUpdatedContact(e.target.value)}  placeholder="contact" />
       </div>
       <div >
        <label htmlFor="occasion"  >Occasion</label>
         <input type="text" name="occasion"  value={updateOccasion}   onChange={(e) => setUpdatedOccasion(e.target.value)} placeholder="occasion" />
       </div>
       <button type="submit">Update Reservation</button>
       </form>
        
        </>
    )
}
export default EditReservationForm;

CodePudding user response:

You haven't /reservation/2 route. That's right

You have /reservations/2 because you have :update in your resources :reservations

You need to change this path in your fetch in JS

To see all the routes run

rails routes

CodePudding user response:

You need to show your routes.rb file, It seems like you don't have any routes defined that handle a PATCH request at "/reservation/2"

  • Related