【问题标题】:Post AJAX request in "vanilla" javascript, no jQuery, in Rails 4在 Rails 4 中使用“vanilla”javascript(没有 jQuery)发布 AJAX 请求
【发布时间】:2015-01-25 12:43:07
【问题描述】:

我已经完成了我的谷歌搜索并搜索了我的问题的解决方案,但由于我的项目非常奇怪,我还没有找到可靠的解决方案。

我正在尝试仅使用“vanilla”javascript(不允许使用 jQuery 或 Rails 助手)制作一个带有 Rails 4 后端的简单聊天应用程序。我有一个 GET Ajax 请求正在工作,它收集所有种子消息数据并将其显示在聊天中。但是,当我尝试向 Rails 后端写入 POST 请求时,我遇到了两个主要问题。它们可能相互关联,也可能不相互关联。

我暂时克服的第一个问题是 422 状态错误(无法处理的实体)。我相信这是因为我的xmlhttp.setRequestHeadervalues 错误?
但是,我不知道它们应该是什么。我通过在我的 Rails MessagesController 中添加 skip_before_filter :verify_authenticity_token 暂时绕过了这个问题。
有没有更优雅的方法来解决这个问题?

这导致我的下一个问题是 400 状态错误(错误请求)。当我在运行服务器时查看终端上的错误时,问题看起来像......

在 2014-11-26 17:32:48 -0800 为 127.0.0.1 开始 POST "/messages"
MessagesController 处理#create as */ *
参数:{"user"=>"namechatsample", "content"=>"messsagechatsample"}
在 4 毫秒内完成 400 个错误请求

ActionController::ParameterMissing(参数缺失或值为空:message):app/controllers/messages_controller.rb:17:in message_params' app/controllers/messages_controller.rb:9:increate'

任何指导和帮助将不胜感激!

这是我的代码。

Ajax 调用

var getRequest = function(callback) {
  var xmlhttp;
  if (window.XMLHttpRequest) {
    xmlhttp = new XMLHttpRequest();
  } else {
    xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
  }
  xmlhttp.onreadystatechange = function() {
    if (xmlhttp.readyState == 4) {
      if (xmlhttp.status == 200) {
        data = JSON.parse(xmlhttp.responseText);
        callback(data.messages)
      } else if (xmlhttp.status == 400) {
        alert('There was an error 400 for GET')
      } else {
        alert('something else other than 200 was returned for GET! This status is ' + xmlhttp.status)
      }
    }
  }
  xmlhttp.open("GET", "/messages", true);
  xmlhttp.send();
}


var postRequest = function(user, message) {
  var xmlhttp;
  if (window.XMLHttpRequest) {
    xmlhttp = new XMLHttpRequest();
  } else {
    xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
  }
  xmlhttp.onreadystatechange = function() {
    if (xmlhttp.readyState == 4) {
      if (xmlhttp.status == 200) {
        data = JSON.parse(xmlhttp.responseText);
        alert('Post ajax call was a success')
      } else if (xmlhttp.status == 400) {
        alert('There was an error 400 for POST')
      } else {
        alert('something else other than 200 was returned for POST! The status is ' + xmlhttp.status)
      }
    }
  }
  xmlhttp.open("POST", "/messages", true);
  xmlhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
  xmlhttp.send("user=" + user + "&content=" + message + "");
}

postRequest("namechatsample", "messsagechatsample")

Rails 4 消息控制器

class MessagesController < ApplicationController
 skip_before_filter  :verify_authenticity_token

 def index #returns last 10 messages
   render :json => Message.last(10)
 end

 def create #makes a new message
   msg = Message.new(message_params)
   msg.save
   render :json => msg
 end


 private
  def message_params
    params.require(:message).permit(:user, :content)
  end
end

如果您认为其他文件或代码位置有问题,请告诉我!

【问题讨论】:

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


    【解决方案1】:

    你有:

     def message_params
         params.require(:message).permit(:user, :content)
     end
    

    这需要在请求中将强参数传递给控制器​​。根据这个声明,json 必须看起来像

     {"message" : {"user" : "someuserthing", "content" : "someusercontent"}}
    

    您看起来并不遥远,但第一步是确保您的应用以该格式传递 JSON。

    顺便说一句,在控制台中查看实际传递的 json 是非常有帮助的。在你的情况下,你说:

     Parameters: {"user"=>"namechatsample", "content"=>"messsagechatsample"}
    

    如您所见,它没有“消息”的根元素。

    祝你好运。

    【讨论】:

      【解决方案2】:

      422 状态错误

      422 错误是因为默认情况下 Rails 通过真实性令牌添加Cross Site Request Forgery (CSRF) prevention measures。如果令牌在 422 状态下无效(或不存在),则在 POST/PUT/DESTROY 请求上返回错误。要解决这个问题,您可以禁用真实性检查(就像您所做的那样),或者您可以在 ajax 请求中发送所需的令牌,如 this answer.

      中所述

      400 状态错误

      这是因为您在控制器中定义的 strong parameters 需要一个消息参数作为发送的参数的一部分 (params.require(:message)...),并且它允许将“内容”值作为嵌套参数。例如,所需的结构需要是:

      :message => {:content => 'message data'}
      

      在 javascript 中,您已将消息的参数名称作为“内容”发送,参数名称需要为“消息 [内容]”。例如:

      xmlhttp.send("message[user]=" + user + "&message[content]=" + message + "");
      

      【讨论】:

      • 感谢Pete 的回复,我已经知道如何使用document.querySelectorAll('meta[name=csrf-token]')[0].content 获取令牌,并且您对嵌套参数的解释是“哦,是的!”我的时刻。谢谢。
      【解决方案3】:

      这导致我的下一个问题是 400 状态错误(错误请求)

      require(:message),但只发送usercontent

      有没有更优雅的方法来解决这个问题?

      是的,如果你根本不想处理 CSRF,你可以把这个放在application.rb

      self.allow_forgery_protection = false
      

      或者,您可以实施正确的 CSRF 处理。 :)

      但是,让我不请自来地补充一点:Rails 不太适合聊天应用程序。理想情况下,你会想要一些彗星般的东西,比如 socket.io。

      【讨论】:

      • 嘿 Amadan,很抱歉我是个菜鸟……但是当你说我需要(:message)但只发送用户和内容时,你能解释一下吗?我的 xmlhttp.send() 是否应该包含消息值?
      • 查看控制器中的message_params。你写的不是我 :) 你可能想要params.require(:user, :content) 而根本不提:message,因为你的数据结构不适合你目前拥有的。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-06-03
      • 1970-01-01
      • 2021-09-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-01-18
      相关资源
      最近更新 更多