我正在Rails中苦苦追求JS AJAX请求。有一个官方指南here,但将它与ES6 JS匹配时遇到了一些困难。提出请求后,我很难将事情传递回前端。
我进行了JS window.onload调用,因为我试图找到用户的屏幕尺寸(以及其他),并将其传递回Rails:
let xhttp = new XMLHttpRequest();
const url = "/users";
xhttp.open("POST", url);
// Some other things added to it...
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 201) {
console.log(this.responseText);
}
};
xhttp.send(JSON.stringify({user_info: userInfo}));
它正在向/ user发布有关会话的一些信息。一切顺利。注意console.log
会跟踪响应,稍后我们将进行介绍。
在我的Rails控制器中:
def create
user_info = params[:user_info].permit!
user_info = user_info.to_s
@fingerprint_user = User.find_or_create_by(fingerprint: user_info)
respond_to do |format|
# NOTE: I have tried a few things here
# format.html { redirect_to @fingerprint_user, notice: "Successfully identified user by fingerprint." }
# format.js
format.json { render json: @fingerprint_user, status: :created, head: :ok }
end
end
JSON发送者工作正常。上面JS中的console.log正确地console.log记录了接收到的JSON。请求以201和JSON形式的@fingerprint_user实例变量响应。
我的问题是返回带有实例变量的ERB JS。如指南中所示,我尝试添加format.js
。然后,请求返回200,以及我的views/users/create.js.erb
文件的内容:
console.log("hello");
但是,实际上不是登录到控制台。
最后,我尝试使用所有格式字段(js,html和json)。这是我的show.html.erb
:
<p>Got user: <%= @fingerprint_user.to_s %> </p>
这是一个更好的views/users/create.js.erb
文件,其中fingerprint
是我的index.html.erb
中的div:
console.log("hello");
$("<%= escape_javascript(render @fingerprint_user) %>").appendTo("#fingerprint");
再次,响应是200,以及适当的html,但这未在页面上呈现。
对JavaScript的AJAX请求的请求不同于对JSON的请求。您实际上不需要加载数据并进行解析,而是实际加载数据,然后通过各种技巧将其评估为当前页面上下文,例如将脚本标签附加到文档中。这是实际的Rails UJS implementation:
processResponse = (response, type) ->
if typeof response is 'string' and typeof type is 'string'
if type.match(/\bjson\b/)
try response = JSON.parse(response)
else if type.match(/\b(?:java|ecma)script\b/)
script = document.createElement('script')
script.setAttribute('nonce', cspNonce())
script.text = response
document.head.appendChild(script).parentNode.removeChild(script)
else if type.match(/\b(xml|html|svg)\b/)
parser = new DOMParser()
type = type.replace(/;.+/, '') # remove something like ';charset=utf-8'
try response = parser.parseFromString(response, type)
response
这就是十年前我们使用JSONP跨域进行AJAX调用来解决CSP的确切方法。
您可以使用以下方法在“原始ajax请求”中模拟相同的内容:
let xhttp = new XMLHttpRequest();
const url = "/users";
xhttp.open("POST", url);
// Some other things added to it...
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 201) {
let script = document.createElement('script');
script.innerHTML = data;
document.querySelector('head').appendChild(script);
}
};
但坦率地说,js.erb
是一个可怕的想法。它使服务器和客户端的责任变得一团糟,并使您的代码很难遵循和推理,并将JS从资产/ Webpack管道中移出,并进入了一些程序垃圾脚本视图。