Ruby on Rails 6 PUT параметры json не установлены

#ruby-on-rails #ruby-on-rails-5

#ruby-on-rails #ruby-on-rails-5

Вопрос:

У меня есть очень простой контроллер Rails 6 под названием BlogsController, есть действие ОБНОВЛЕНИЯ, называемое update . Когда я пытаюсь отправить json с помощью postman, он возвращает 400 неверных запросов, в журналах я нахожу, что есть ТОЛЬКО ОДИН??? идентификатор параметра, мое содержимое json игнорируется. Это очень простая вещь, которая должна работать, но это не так. Это меня смущает. Пожалуйста, помогите.

Это код контроллера:

 class BlogsController < ApplicationController
  skip_before_action :verify_authenticity_token
  before_action :set_blog, only: %i[ show edit update destroy ]

  # GET /blogs or /blogs.json
  def index
    @blogs = Blog.all
  end

  # GET /blogs/1 or /blogs/1.json
  def show
  end

  # GET /blogs/new
  def new
    @blog = Blog.new
  end

  # GET /blogs/1/edit
  def edit
  end

  # POST /blogs or /blogs.json
  def create
    @blog = Blog.new(blog_params)

    respond_to do |format|
      if @blog.save
        format.html { redirect_to @blog, notice: "Blog was successfully created." }
        format.json { render :show, status: :created, location: @blog }
      else
        format.html { render :new, status: :unprocessable_entity }
        format.json { render json: @blog.errors, status: :unprocessable_entity }
      end
    end
  end

  # PATCH/PUT /blogs/1 or /blogs/1.json
  def update
    respond_to do |format|
      if @blog.update(blog_params)
        format.html { redirect_to @blog, notice: "Blog was successfully updated." }
        format.json { render :show, status: :ok, location: @blog }
      else
        format.html { render :edit, status: :unprocessable_entity }
        format.json { render json: @blog.errors, status: :unprocessable_entity }
      end
    end
  end

  # DELETE /blogs/1 or /blogs/1.json
  def destroy
    @blog.destroy
    respond_to do |format|
      format.html { redirect_to blogs_url, notice: "Blog was successfully destroyed." }
      format.json { head :no_content }
    end
  end

  private
    # Use callbacks to share common setup or constraints between actions.
    def set_blog
      @blog = Blog.find(params[:id])
    end

    # Only allow a list of trusted parameters through.
    def blog_params
      params.require(:blog).permit(:title, :content)
    end
end
 

Я делаю PUT json /blogs/1 это с заголовком типа содержимого, установленным в application / json

 Content-Type: application/json
 

элемент для обновления выглядит следующим образом:

 { "blog": {"id":1,"title":"Blog one","content":"Blog 1 Test Sem"} }
 

сообщение об ошибке в журналах выглядит так:

 2 [2] Started PUT "/blogs/1" for 54.86.50.139 at 2021-12-02 10:38:14  0000
2 [2] Processing by BlogsController#update as JSON
2 [2]   Parameters: {"id"=>"1"}
2 heroku[router]: at=info method=PUT path="/blogs/1" host=ror-backend-angular-13.herokuapp.com request_id=2f1982a8-bbe1-41b0-bb3c-09b7e3db7caa fwd="54.86.50.139" dyno=web.1 connect=0ms service=7ms status=400 bytes=223 protocol=https
2 [2] Completed 400 Bad Request in 3ms (ActiveRecord: 0.9ms | Allocations: 441)
2 FATAL -- : [2]
2 [2] ActionController::ParameterMissing (param is missing or the value is empty: blog
2: Did you mean?  action
2: controller
2: id):
2: [2]
2: [2] app/controllers/blogs_controller.rb:68:in `blog_params'
2 [2] app/controllers/blogs_controller.rb:41:in `block in update'
2 [2] app/controllers/blogs_controller.rb:40:in `update'
 

как вы можете видеть в журналах, есть только один анализируемый параметр: {"id"=>"1"} . Почему JSON тело содержимого игнорируется? Это что-то совершенно сумасшедшее, это убивает меня.

Комментарии:

1. Мой совет — написать интеграционный тест (или запросить спецификацию, если вы используете RSpec) — вместо использования Postman. Таким образом, вы можете поделиться им с нами, и мы сможем воспроизвести результаты. Это также означает, что вы тратите свое время на защиту от будущих регрессий вместо того, чтобы правильно использовать входные данные postman / curl, что является пустой тратой времени. в 99% случаев это просто ошибка пользователя, и то, что вы делаете со своей стороны, является для нас черным ящиком.

2. Здесь также есть две небольшие однотипные вещи — PATCH является основным методом обновления с 2012 года, но Rails по-прежнему генерирует маршруты PUT для обратной совместимости, и вам не нужно / не нужно передавать идентификатор в теле запроса, поскольку он является частью URL.

Ответ №1:

Я не использовал Postman, но я могу помочь вам с помощью cURL для отправки данных JSON в ваш Rails API. Пожалуйста, ознакомьтесь с инструкциями ниже:

Для отправки JSON первым шагом является помещение данных (для отправки в API) в формате JSON в файл, скажем my_data.json , и сохранение его в местоположение, скажем /home/jignesh , а затем использование следующего URL-адреса cURL для отправки запроса**:

 curl -X PUT -H "Content-type: application/json" --data-binary @/home/jignesh/my_data.json "http://<API_URL>/blogs/<BLOG_ID>"
 

Ответ №2:

Вы отправляете в blogs/1 конечную точку, а не blogs/1.json в соответствии с журналом. Код игнорирует параметры (возможно, они не отправляются почтальоном должным образом — вы не указали, что вы сделали с этой целью, но, конечно, они игнорируются!). Я предполагаю, что, передавая blogs/1 вам код, вы принимаете его как PUT to blogs с параметром 1 , взятым из URL. Тело вашего запроса игнорируется.

Комментарии:

1. спасибо за ваше предложение. Независимо от того, ПОМЕЩАЮ ли я в blogs /1 или blogs / 1.json, не имеет значения, выдается та же ошибка.

2. Хорошо, итак, если вы используете byebug (или что-то еще) в верхней части вашего контроллера, как там выглядят параметры. (Вместо того, чтобы полагаться на журнал.) Потому что это 1 откуда-то берется. Что произойдет, если вы ВВЕДЕТЕ to blogs/2 с тем же сообщением JSON?

3. Если вы посмотрите на журнал, Rails явно обрабатывает запрос как JSON. Я бы предположил, что отправляется правильный тип контента. Использование расширения — это только один из способов установки требуемого формата.