Javascript Rails 中的 POST 422(不可处理实体)?由于路线或控制器?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/27098239/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-22 23:42:10  来源:igfitidea点击:

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

javascriptruby-on-railsrubyajaxhttprequest

提问by piratetone

I'm trying to give users on my website "points" or "credits" for tweeting about out the brand name.

我试图在我的网站上为用户提供“积分”或“积分”,以便他们发布关于品牌名称的推文。

I have the fancy twitter widget on the appropriate view...

我在适当的视图上有漂亮的推特小部件......

<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>    

I have the JS all written up and pretty....

我把 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);
  }); 
});

Now the problem is either in the controller OR in the routes (where I'm posting). I think the routes are fine because the POST is almost working, because this is the description of the error on wikipedia - "422 Unprocessable Entity (WebDAV; RFC 4918) The request was well-formed but was unable to be followed due to semantic errors."

现在问题出在控制器或路由中(我发布的地方)。我认为路由很好,因为 POST 几乎可以正常工作,因为这是维基百科上对错误的描述 - “422 Unprocessable Entity (WebDAV; RFC 4918) The request is well-formed but is无法被遵循由于语义错误.”

So, do you guys see anything wrong with my ruby code in the controller?

那么,你们看到我控制器中的 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

And in my routes.rb, it's pretty straight forward, so I doubt there's anything wrong here...

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

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

Where oh where is this error? I clearly don't know smack about HTTP requests.

哪里哦这个错误在哪里?我显然不了解 HTTP 请求。

回答by piratetone

I got it working!

我让它工作了!

I added a...

我加了一个...

skip_before_action :verify_authenticity_token

to the controller.

到控制器。

The issue was found when checking out the logs and seeing that the CSRF token could not be verified.

在查看日志并看到无法验证CSRF令牌时发现了该问题。

回答by barlop

ihaztehcodez(who was last active in 2016 so it won't help nudging him to post an answer) mentions that the skip_before_action :verify_authenticity_tokentechnique is not so secure 'cos you lose forgery protection.

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

they mention that the best/secure/'better practise', solutions are mentioned here WARNING: Can't verify CSRF token authenticity rails

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

e.g.

例如

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

or

或者

$.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);
  }
});

or

或者

putting this within an ajax request

把它放在一个ajax请求中

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

回答by Shekhar Patil

Same problem I faced. It sorts out after adding

我遇到了同样的问题。添加后就搞定了

skip_before_action :verify_authenticity_token

skip_before_action :verify_authenticity_token

at the top of your controller where your JS is calling or sending data.

在 JS 调用或发送数据的控制器顶部。

class UserController < ApplicationController
    skip_before_action :verify_authenticity_token
    def create
    end
end

as shown in code snippet.

如代码片段所示。

回答by Lex

If you're including Rails meta data in the HTML header with <%= csrf_meta_tags %>it'll generate the following.

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

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

You can pull the CRSF token from the meta data and pass it into your async request. Using the native js fetchmethod you can pass it in as a x-csrf-tokenheader.

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

This is a trimmed onSave handler for a React component that enhances a standard Rails form.

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

  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);
    });
  }

Forgery protection is a good idea. This way we stay secure and don't mess with our Rails configuration.

防伪是个好主意。这样我们就可以保持安全并且不会弄乱我们的 Rails 配置。

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

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