Ruby on Rails 6 PUT json 参数未设置

Posted

技术标签:

【中文标题】Ruby on Rails 6 PUT json 参数未设置【英文标题】:Ruby on Rails 6 PUT json parameters are not set 【发布时间】:2022-01-08 20:49:53 【问题描述】:

我有一个非常简单的 Rails 6 控制器,叫做 BlogsController,有一个 UPDATE 动作,叫做 update。当我尝试使用邮递员提交 json 时,它返回 400 Bad Request,在日志中我发现只有一个???参数id,我的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 将 Content-Type 标头设置为 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"=&gt;"1"。为什么JSON 内容主体被忽略?这简直太疯狂了,简直要死我了。

【问题讨论】:

我的建议是编写集成测试(如果您使用的是 RSpec,则请求规范) - 而不是使用 Postman。这样您就可以与我们分享它,我们可以重现结果。这也意味着您将时间花在防范未来的回归上,而不是让您的邮递员/卷发输入恰到好处,这浪费了时间。 99% 的时间它只是简单的用户错误,而您所做的对我们来说是一个黑匣子。 这里还有两个小东西 - PATCH is the primary method for updates since way back in 2012 但 Rails 仍然会生成 PUT 路由以实现向后兼容性,并且您不需要/不想在请求正文中传递 id,因为它是一部分网址。 【参考方案1】:

我没有使用过 Postman,但我可以帮助您使用 cURL 将 JSON 数据提交到 Rails API。请在下面找到说明:

要发送 JSON,第一步是将 JSON 格式的数据(要发送到 API)放入一个文件中,例如 my_data.json,并将其保存到一个位置,例如 /home/jignesh,然后使用以下 cURL URL发送请求**:

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

【讨论】:

【参考方案2】:

根据日志,您正在 PUT 到 blogs/1 端点,而不是 blogs/1.json。代码忽略了参数(也许邮递员没有正确发送它们 - 你没有表明你为此做了什么 - 但它们肯定被忽略了!)。我的假设是,通过 PUT 到 blogs/1,您的代码会将其作为 blogs 的 PUT,参数 1 取自 URL。您的请求正文将被忽略。

【讨论】:

感谢您的建议。无论我 PUT 到 blogs/1 还是 blogs/1.json 都没有区别,都会抛出同样的错误。 好的,所以如果你在控制器顶部使用 byebug(或其他),那里的参数是什么样的。 (而不是依赖日志。)因为它是从某个地方得到1 的。如果您使用相同的 JSON 消息 PUT 到 blogs/2 会发生什么? 如果您查看日志,Rails 显然将请求视为 JSON。我会假设正在发送正确的内容类型。使用扩展只是设置请求格式的一种方式。

以上是关于Ruby on Rails 6 PUT json 参数未设置的主要内容,如果未能解决你的问题,请参考以下文章

Bootstrap (5) Javascript 在 package.json 修订后不起作用 (Ruby on Rails 6)

Ruby on rails -- Jquery 在另一个 post 请求之前没有提交 put 请求

在 Ruby on Rails 中,如何渲染 JSON?

Ruby on Rails 高级 JSON 序列化

Ruby on Rails 路由解析

Ruby on Rails JSON 序列化