轨道:轨道中的 POST 422(不可处理的实体)?由于路由或控制器

Rails: POST 422 (Unprocessable Entity) in Rails? Due to the routes or the controller?

本文关键字:轨道 于路由 控制器 路由 可处理 POST 实体      更新时间:2023-09-26

我试图在我的网站上给用户"积分"或"学分",以在推特上发布有关品牌名称的信息。

我在适当的视图上有花哨的推特小部件......

<p><a  href="https://twitter.com/share" class="twitter-share-button" data-text="Check Out This Awesome Website Yay" data-via="BrandName" data-hashtags="ProductName">Tweet</a>
<div id="credited"></div>
<script>window.twttr = (function (d, s, id) {
  var t, js, fjs = d.getElementsByTagName(s)[0];
  if (d.getElementById(id)) return;
  js = d.createElement(s); js.id = id;
  js.src= "https://platform.twitter.com/widgets.js";
  fjs.parentNode.insertBefore(js, fjs);
  return window.twttr || (t = { _e: [], ready: function (f) { t._e.push(f) } });
}(document, "script", "twitter-wjs"));
</script>    

我把JS都写好了,很漂亮....

function creditTweet() {
  $.post(
    "/credit_tweet",
    {},
    function(result) {
      var text;
      if (result.status === "noop") {
        text = "Thanks for sharing already!";
      } else if (result.status === "ok") {
        text = "5 Kredit Added";
      }
      $("#credited").html(text);
    }
  );
}
$(function() {
  twttr.ready(function (twttr) {
    window.twttr.events.bind('tweet', creditTweet);
  }); 
});

现在问题要么在控制器中,要么在路由中(我发布的地方)。我认为路线很好,因为 POST 几乎可以工作,因为这是维基百科上错误的描述 - "422 无法处理的实体 (WebDAV;RFC 4918)请求格式正确,但由于语义错误而无法遵循。

那么,你们发现我的 ruby 代码在控制器中有什么问题吗?

class SocialKreditController < ApplicationController
    TWEET_CREDIT_AMOUNT = 5
  def credit_tweet
    if !signed_in?
      render json: { status: :error }
    elsif   current_user.tweet_credited
        Rails.logger.info "Not crediting #{ current_user.id }"
        render json: { status: :noop }
      else
        Rails.logger.info "Crediting #{ current_user.id }"
        current_user.update_attributes tweet_credited: true
        current_user.add_points TWEET_CREDIT_AMOUNT
        render json: { status: :ok }
      end
  end
end

在我的 routes.rb 中,它非常简单,所以我怀疑这里有什么问题......

  get 'social_kredit/credit_tweet'
  post '/credit_tweet' => 'social_kredit#credit_tweet'

哦,这个错误在哪里?我显然不知道HTTP请求。

我让它工作了!

我添加了一个...

skip_before_action :verify_authenticity_token

到控制器。

在签出日志并看到无法验证 CSRF 令牌时发现此问题。

ihaztehcodez(他最后一次活跃是在2016年,所以无助于推动他发布答案)提到skip_before_action :verify_authenticity_token技术不是那么安全,因为你失去了伪造保护。

他们提到最好/安全/"更好的做法",这里提到了解决方案 警告:无法验证 CSRF 令牌的真实性轨道

例如

$.ajaxSetup({
  headers: {
    'X-CSRF-Token': $('meta[name="csrf-token"]').attr('content')
  }
});

$.ajax({ url: 'YOUR URL HERE',
  type: 'POST',
  beforeSend: function(xhr) {xhr.setRequestHeader('X-CSRF-Token', $('meta[name="csrf-token"]').attr('content'))},
  data: 'someData=' + someData,
  success: function(response) {
    $('#someDiv').html(response);
  }
});

将其放在 Ajax 请求中

headers: {
  'X-Transaction': 'POST Example',
  'X-CSRF-Token': $('meta[name="csrf-token"]').attr('content')
},

面临的同样问题。添加后整理

skip_before_action :verify_authenticity_token

位于控制器顶部,您的 JS 正在调用或发送数据。

class UserController < ApplicationController
    skip_before_action :verify_authenticity_token
    def create
    end
end

如代码片段所示。

我在处理仅限 Rails 6 API 的应用程序时遇到了这个挑战。

我遵循了这里的答案 - Rails:如何在 Rails API 模式下实现protect_from_forgery

以在 Rails API 模式下实现protect_from_forgery,但是当我从 Postman 发送帖子请求时,我仍然遇到Can't verify CSRF token authenticity错误,然后是422 Unprocessable Entity错误:

Started POST "/api/v1/programs" for ::1 at 2021-02-23 18:42:49 +0100
Processing by Api::V1::ProgramsController#create as JSON
  Parameters: {"program"=>{"name"=>"Undergraduate", "code"=>"UD", "affiliate_status"=>false, "motto"=>"Our motto is ...", "description"=>"This is a new program", "school_id"=>1}}
Can't verify CSRF token authenticity.
  TRANSACTION (0.3ms)  BEGIN
  ↳ app/controllers/api/v1/programs_controller.rb:27:in `create'
  Baserecord::School Load (0.3ms)  SELECT "schools".* FROM "schools" WHERE "schools"."id" = $1 LIMIT $2  [["id", 1], ["LIMIT", 1]]
  ↳ app/controllers/api/v1/programs_controller.rb:27:in `create'
  TRANSACTION (0.4ms)  ROLLBACK
  ↳ app/controllers/api/v1/programs_controller.rb:27:in `create'
Completed 422 Unprocessable Entity in 30ms (Views: 0.8ms | ActiveRecord: 6.9ms | Allocations: 13172)

这是我解决的

该问题是由我的模型中的验证错误引起的。我为正在调用的控制器添加到模型中的验证失败。我不得不在发出请求以查找错误后检查邮递员返回的响应的正文

{
    "affiliate_status": [
        "can't be blank"
    ]
}

一旦我修复了这个答案之后的错误 - Rails:ActiveRecord 在设置随机布尔属性时验证失败,之后一切正常。

就这样。

我希望这有帮助

POST 请求中更新模型时可能会发生 422:

例如 @user.update!(email: nil) in users#update 如果对电子邮件进行验证,例如 validates :email, presence: true

> 如果你在HTML头中包含Rails元数据,<%= csrf_meta_tags %>它将生成以下内容。

<meta name="csrf-param" content="authenticity_token" />
<meta name="csrf-token" content="ihwlaOLL232ipKmWYaqbSZacpJegQqooJ+Cj9fLF2e02NTQw7P/MfQyRuzruCax2xYWtEHWsb/uqiiZP6NWH+Q==" />

您可以从元数据中提取 CRSF 令牌并将其传递到异步请求中。使用本机 js fetch 方法,您可以将其作为 x-csrf-token 标头传入。

这是一个经过修剪的 onSave 处理程序,用于增强标准 Rails 表单的 React 组件。

  onSaveHandler = (event) => {
    const data = "Foo Bar";
    const metaCsrf = document.querySelector("meta[name='csrf-token']");
    const csrfToken = metaCsrf.getAttribute('content');
    fetch(`/posts/${this.props.post_id}`, {
      method: "PUT",
      body: JSON.stringify({
        content: data
      }),
      headers: {
        'x-csrf-token': csrfToken,
        'content-type': 'application/json',
        'accept': 'application/json'
      },
    }).then(res => {
      console.log("Request complete! response:", res);
    });
  }

防伪保护是个好主意。通过这种方式,我们可以保持安全,不会弄乱我们的 Rails 配置。

使用 gem 'rails', '~> 5.0.5' & "react": "^16.8.6",