Home > Software design >  Rails not redirecting on PUT request, sending 406 back instead
Rails not redirecting on PUT request, sending 406 back instead

Time:04-23

I'm working on a bell schedule creator for a school project I'm working on. The bell schedule creation on the client is handled with a React component, and when it comes time to update, the component calls this fetch request:

fetch(`/bell-schedules/${this.state.updatingId}`, {
                method: 'PUT',
                mode: 'cors',
                credentials: 'same-origin',
                headers: {
                    'Content-Type': 'application/json',
                    'Accept': 'text/html',
                },
                redirect: "follow",
                referrerPolicy: 'no-referrer',
                body: JSON.stringify({ name: this.state.name, schedule: json})})

On the server, these requests are handled by the BellSchedulesController, and the method for handling this type of route is coded as so:

# PUT /bell-schedules/:id
  def update
    set_bell_schedule
    respond_to do |format|
      if @schedule.update(name: params[:name], schedule: params[:schedule])
        redirect_to action: 'index'
      else
        head 400
      end
    end
  end

Index is a simple method that gets all the bell schedules and renders them in a table; that method works fine, other routes point to it and it renders normally. Unfortunately, when I send this PUT request, rather than getting a redirect to that page showing the table of bell schedules, I instead get back a 406 Not Acceptable. I also know that the bell schedule is actually updating, I've inspected the entry in the rails console.

How do I handle redirects in PUT requests? I'm also having an issue similar to this in a POST request, but I've found a hack around it there; that hack won't work in this one.

CodePudding user response:

The solution is partially explained in ActionController::Redirecting as well as this answer for an express API.

Using a 303 status code should allow for the redirect to go through.

# PUT /bell-schedules/:id
  def update
    set_bell_schedule
    respond_to do |format|
      if @schedule.update(name: params[:name], schedule: params[:schedule])
        redirect_to action: 'index', status: :see_other
      else
        head 400
      end
    end
  end

Explanation

Standard 301/302 redirects for dangerous HTTP methods (anything other than GET) generally won't be honored by the browser.

A typical redirect response to a GET request indicates that the requested resource has moved (temporarily or permanently).

For PATCH/PUT/POST/DELETE, The browser has to assume that the resource was found at the expected location, but its data has changed since the initial request was made. The server is just informing the client that the response for this action exists at another location.

For the sanctity of the HTTP contract, a different status code is needed to indicate this situation. 303 informs the client of the location of this response location and suggests that it can be accessed with a GET request.

CodePudding user response:

Googling your problem it seems to come from the respond_to ... |format| block, try getting rid of it and see if it helps. You don't seem to be using it correctly, you are not doing anything with the format and maybe that's why it's blowing up.

  • Related