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

时间:2014-11-24 05:12:17

标签: javascript ruby-on-rails ruby ajax httprequest

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

我在适当的视图上有精美的推特小部件......

<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 Unprocessable Entity(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请求的信息。

5 个答案:

答案 0 :(得分:49)

我搞定了!

我添加了......

skip_before_action :verify_authenticity_token

到控制器。

检查日志时发现问题,并发现无法验证CSRF令牌。

答案 1 :(得分:0)

我面临同样的问题。 它在添加

后排除

skip_before_action:verify_authenticity_token

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

class UserController < ApplicationController
    skip_before_action :verify_authenticity_token
    def create
    end
end

如代码段所示。

答案 2 :(得分:0)

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

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

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

这是为React组件修剪的onSave处理函数,用于增强标准的Rails表单。

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

答案 3 :(得分:0)

ihaztehcodez(上一次活跃于2016年,因此无助于推动他发布答案)提到skip_before_action :verify_authenticity_token技术并不是那么安全,因为您会失去伪造保护。

他们提到最佳/安全/“更好的实践”解决方案WARNING: Can't verify CSRF token authenticity rails

例如

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

答案 4 :(得分:0)

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

我按照这里的答案 - Rails: How to implement protect_from_forgery in Rails API mode 在 Rails API 模式下实现了protect_from_forgery,但是当我发送 post 时,我仍然遇到 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)

这是我解决的

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

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

一旦我修复了此答案后的错误 - Rails: Validation fails for ActiveRecord in setting a random Boolean Attribute,之后一切正常。

仅此而已。

我希望这会有所帮助