Ruby On Rails 3,form_tag 远程响应 Ajax 请求
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4020393/
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
Ruby On Rails 3, form_tag remote on responding to Ajax request
提问by Kunal
thanks for reading this post. I've been stuck on an issue with RoR for the past few days. I have a form under index.html.erb as:
感谢您阅读这篇文章。过去几天我一直被困在 RoR 的问题上。我在 index.html.erb 下有一个表单:
<head>
<title>Ajax List Demo</title>
<%= javascript_include_tag :defaults %>
<%= csrf_meta_tag %>
</head>
<body>
<h3>Add to list using Ajax</h3>
<% form_tag :action => :list , :method=>:get, :remote=>true do %>
Enter the public url:<%= text_field_tag 'url' ,'', :size => 80 %>
<%= submit_tag "Find" %>
<% end %>
<div id="my_list">
</div>
</body>
In the controller I have:
在控制器中,我有:
def list
puts "here!!!!"
reader = Reader.new
@profiles = reader.processURL(params[:url]) #profileList =
respond_to do |format|
#format.html { render :partial=>true, :locals => { :profiles => @profiles}}#{ render :partial=>'profiles/list',:layout => false, :locals => { :profiles => @profiles}}
format.js {render :content_type => 'text/javascript', :locals => { :profiles => @profiles}}
# index.html.erb
# format.rss render :partial=>'profiles/list',:layout => false, :locals => { :profiles => @profiles}
end
And a js file for remote UJS as list.js.erb
以及一个用于远程 UJS 的 js 文件作为 list.js.erb
$("#my_list").html("<%= escape_javascript(render(:partial => "list"))%>");
The issue is I cannot get the results to render the partial _list.html.erb, in the div tag my_list. I get a blank page, 406 error. If I un-comment the render html code in the controller I get the partial back rendered in the browser. I am kind of stuck, I want to submit the form and the results to pop in the my_list div. I'm new to rails so if I'm missing something obvious don't hesitate to point it out to me....I'm definitely willing to try.
问题是我无法在 div 标签 my_list 中获得渲染部分 _list.html.erb 的结果。我得到一个空白页,406 错误。如果我取消注释控制器中的渲染 html 代码,我会在浏览器中返回部分渲染。我有点卡住了,我想提交表单和结果以弹出 my_list div。我是 Rails 的新手,所以如果我遗漏了一些明显的东西,请毫不犹豫地向我指出......我绝对愿意尝试。
Changed it to this:
改成这样:
<html>
<head>
<title>Ajax List Demo</title>
<h1>Listing posts</h1>
<%= javascript_include_tag 'jquery.js' %>
<%= csrf_meta_tag %>
</head>
<body>
<h3>Add to list using Ajax</h3>
<% form_tag :action => :doit , :method=>:get, :remote=>true do %>
Enter the public url:<%= text_field_tag 'url' ,'', :size => 80 %>
<%= submit_tag "Find" %>
<% end %>
<div id="my_list">
</div>
Controller:
控制器:
def doit
puts "here!!!!"
reader = Reader.new
@profiles = reader.processURL(params[:url])
respond_to do |format|
# format.html {render :partial=>true, :locals => { :profiles => @profiles}}#{ render :partial=>'profiles/list',:layout => false, :locals => { :profiles => @profiles}}
format.js #{render :content_type => 'text/javascript', :locals => { :profiles => @profiles}}
# index.html.erb
# format.rss render :partial=>'profiles/list',:layout => false, :locals => { :profiles => @profiles}
end
JS _doit.js.erb $("#my_list").html("<%= escape_javascript(render(:partial => "doit"))%>");
JS _doit.js.erb $("#my_list").html("<%= escape_javascript(render(:partial => "doit"))%>");
And finally a partial:
最后是部分:
_doit.html.erb.
_doit.html.erb。
However I am still getting the 406 error, I dont have a duplicate _doit js or erb. Does anything standout as incorrect from this? Thanks again!
但是我仍然收到 406 错误,我没有重复的 _doit js 或 erb。有什么突出的不正确吗?再次感谢!
Another update:
另一个更新:
I think the form is not rendered correctly:
我认为表单未正确呈现:
This rendered:
这呈现:
<% form_tag :action => :doit , :remote=>true, :id => 'myform' do %>
Enter the public url:<%= text_field_tag 'url' ,'', :size => 80 %>
<%= submit_tag "Find" %>
<% end %>
This:
这个:
<form accept-charset="UTF-8" action="/home/doit?id=myform&remote=true" method="post">
<div style="margin:0;padding:0;display:inline">
<input name="utf8" type="hidden" value="✓" />
<input name="authenticity_token" type="hidden" value="MLuau4hvfdGO6FrYCzE0c0JzwHhHKZqjmV49U673sK8=" />
</div> Enter the public url:
<input id="url" name="url" size="80" type="text" value="" />
<input name="commit" type="submit" value="Find" />
<input name="commit" type="submit" value="Find" />
Its adding my remote tag and id to the query string, isnt this wrong?
它将我的远程标签和 id 添加到查询字符串中,这不是错误吗?
Ok finally got a clue forms need to be bracketed:
好吧,终于得到了需要括号括起来的线索形式:
<%= form_tag( { :action => 'doit' }, :multipart => true, :remote=>true, :id => 'myform' ) do %>
Ok last update tonight: Now I get in the logs:
好的,今晚最后一次更新:现在我进入日志:
Started POST "/home/doit" for 127.0.0.1 at Wed Oct 27 22:40:55 -0400 2010 here!!!! Processing by HomeController#doit as JS Parameters: {"commit"=>"Find", "url"=>"http://www.facebook.com/people/James-Stewart/653161299", "authenticity_token"=>"MLuau4hvf dGO6FrYCzE0c0JzwHhHKZqjmV49U673sK8=", "utf8"=>"Γ£?"} Rendered home/_doit.html.erb (4.0ms) Rendered home/doit.js.erb (9.0ms) Completed 200 OK in 807ms (Views: 40.0ms | ActiveRecord: 0.0ms)
2010 年 10 月 27 日星期三 22:40:55 -0400 在这里为 127.0.0.1 开始发布“/home/doit”!!!!由 HomeController#doit 处理为 JS 参数:{"commit"=>"Find", "url"=>"http://www.facebook.com/people/James-Stewart/653161299", "authenticity_token"=>" MLuau4hvf dGO6FrYCzE0c0JzwHhHKZqjmV49U673sK8=", "utf8"=>"Γ£?"} 渲染 home/_doit.html.erb (4.0ms) 渲染 home/doit.js.erb (9.0ms) in 80s70ms OK Completed 2070ms | 活动记录:0.0ms)
I see as JS and it says it renders my js/partial. However I am getting nothing on my_list div. My JS file:
我看到了 JS,它说它呈现我的 js/partial。但是我在 my_list div 上一无所获。我的JS文件:
$("#my_list").html("<%= escape_javascript(render(:partial => "doit"))%>");
My html.erb form file has now:
我的 html.erb 表单文件现在有:
<script$('#myform').bind('ajax:success', function(evt, data, status, xhr){
xhr.responseText;
});></script>
Its like the form does nothing, which is a good sign, no more 406 error. I know this is close, if anyone can point what I need to do in the js that would be great otherwise I'll take a break and try tmrw.
就像表单什么都不做一样,这是一个好兆头,不再出现 406 错误。我知道这很接近了,如果有人能指出我需要在 js 中做的事情那会很棒,否则我会休息一下并尝试 tmrw。
Ok I think its getting a response back just not rendering as you pointed out would be the issue yesterday Steve.
好的,我认为它得到的回应只是没有像你指出的那样呈现昨天史蒂夫的问题。
Debugging the JS on Firebug I see the html I want rendered in the div, for this:
在 Firebug 上调试 JS 我看到我想在 div 中呈现的 html,为此:
http://localhost:3000/javascripts/prototype.js?1285674435/event/seq/1
Which means I think I am getting the JS response back now.
这意味着我认为我现在得到了 JS 响应。
I have this on the form page:
我在表单页面上有这个:
<script>$('#myform').bind('ajax:success', function(evt, data, status, xhr){
$('#my_list').html(eval(xhr.responseText));
});</script>
Inspections say it doesnt know what myform is, but I put :id => 'myform' in the Rails code.
检查说它不知道 myform 是什么,但我将 :id => 'myform' 放在 Rails 代码中。
Again all thanks, I got a ton of help here and I want to share how I finally got it working back to the community.
再次感谢,我在这里得到了很多帮助,我想分享我如何最终让它回到社区。
The, js file for the method doit(def. need a better controller action name) is doit.js
方法 doit(定义。需要一个更好的控制器动作名称)的 js 文件是 doit.js
The code was ultimately:
代码最终是:
$("my_list").update("<%= escape_javascript(render(:partial => "doit"))%>");
For some reason leaving it as #my_list wouldn't be found in firefox, I had to use firebug to finally figure this out.
出于某种原因,将其保留为在 firefox 中找不到 #my_list,我不得不使用 firebug 来最终解决这个问题。
Obviously this is different from the way suggested below, and I am going to place the js script back into the form and remove the .js.erb file and see how that works works. I suppose I just render the partial in the format.js response? Also where does everyone find info on writing the UJS files? I know nothing about the syntax for anything starting with $.
显然这与下面建议的方式不同,我将把 js 脚本放回表单并删除 .js.erb 文件,看看它是如何工作的。我想我只是在 format.js 响应中呈现部分?另外,每个人都在哪里可以找到有关编写 UJS 文件的信息?我对以 $ 开头的任何内容的语法一无所知。
Again thanks for the help, finally feel like I am making progress on learning rails.
再次感谢您的帮助,终于感觉我在学习 Rails 方面取得了进展。
回答by jangosteve
I posted this answer on Hacker News, but figured the Stack Overflow community might benefit as well :-)
我在 Hacker News 上发布了这个答案,但我认为 Stack Overflow 社区也可能受益 :-)
In Rails 3, the javascript drivers are very hands-off (i.e. unobtrusive). The problem you're having is that your app is returning to the browser a string of javascript, but there is nothing in the page that is then executing that javascript in the context of the page.
在 Rails 3 中,javascript 驱动程序非常不干涉(即不显眼)。您遇到的问题是您的应用程序正在向浏览器返回一串 javascript,但页面中没有任何内容在页面上下文中执行该 javascript。
The rails.js ujs driver binds to forms and links with data-remote=true, which is what the :remote => trueis doing, to make them submit their requests remotely, but that is where the Rails magic stops.
rails.js ujs 驱动程序绑定到表单并使用 链接data-remote=true,这就是它:remote => true正在做的事情,让他们远程提交他们的请求,但这就是 Rails 魔法停止的地方。
The good news is that the remote requests fires off some events you can bind to, which give you access to the data returned by the server (which fire off in the following order):
好消息是远程请求会触发一些您可以绑定的事件,这些事件使您可以访问服务器返回的数据(按以下顺序触发):
ajax:before
ajax:loading
ajax:success
ajax:complete
ajax:failure
ajax:after
You need to bind an event to the ajax:successevent of your form. So, if your form had the id "myform", you'd want something like this on your page:
您需要将事件绑定到ajax:success表单的事件。因此,如果您的表单的 id 为“myform”,您会希望在您的页面上有这样的内容:
$('#myform').bind('ajax:success', function(evt, data, status, xhr){
eval(xhr.responseText);
});
xhr.responseTextis what your server returns, so this simply executes it as javascript.
xhr.responseText是您的服务器返回的内容,因此这只是将其作为 javascript 执行。
Of course, it's proper to also bind to the failure event with some error handling as well.
当然,也可以通过一些错误处理绑定到失败事件。
I usually don't even use the action.js.erb method of returning javascript, I just have my controller render the HTML partial, and then I have a binding like this in the page:
我通常甚至不使用返回 javascript 的 action.js.erb 方法,我只是让我的控制器呈现 HTML 部分,然后我在页面中有这样的绑定:
$('#myform').bind('ajax:success', function(evt, data, status, xhr){
$('#target-div').html(xhr.responseText);
});
I'm actually in the middle of writing a full article on this, but hopefully this is enough to get you going.
我实际上正在写一篇关于这个的完整文章,但希望这足以让你前进。
EDIT: I finished that article, fully explaining remote links and forms in Rails 3. Maybe it will help:
编辑:我完成了那篇文章,充分解释了 Rails 3 中的远程链接和表单。也许它会有所帮助:
回答by RobR
If you look at the rendered source of your page, you should notice an error in the fields attributes.
如果您查看页面的呈现源,您应该注意到 fields 属性中存在错误。
The correct way to do it is as follows:
正确的做法如下:
<%= form_tag({:action => 'list'}, :remote => true %>
Notice the curly brackets, very important! Alternatively you could have done:
注意大括号,非常重要!或者你可以这样做:
<%= form_tag('list', :remote => true %>
回答by monocle
Do you have 2 partials named '_list'? Maybe that's causing problems and you should just a little more specific:
你有 2 个名为 '_list' 的部分吗?也许这会导致问题,您应该更具体一点:
$("#my_list").html("<%= escape_javascript(render(:partial => "list.html.erb"))%>");
I'm not sure if this helps, but are if you using in IE be aware that IE sends some headers that screw with how your controller responds. So you may be sending an Ajax request with IE, but your Rails app thinks its just a plain html request.
我不确定这是否有帮助,但是如果您在 IE 中使用,请注意 IE 会发送一些与控制器响应方式有关的标头。因此,您可能正在使用 IE 发送 Ajax 请求,但您的 Rails 应用程序认为它只是一个普通的 html 请求。
I've had to setup jQuery to first erase the current headers and then add just the javascript header:
我必须设置 jQuery 以首先擦除当前标题,然后只添加 javascript 标题:
$.ajaxSetup({
'beforeSend': function(xhr) {xhr.setRequestHeader("Accept",'');xhr.setRequestHeader("Accept", "text/javascript")}
})
})
回答by icecream
Using listas your function name in the controller may be the problem. That name is used internally by Rails.
使用list控制器作为你的函数名称可能是问题。该名称由 Rails 内部使用。
回答by sandeep rajbhandari
Rails 5.1 introduced rails-ujs, which changes the parameters of these event handlers. The following should work:
Rails 5.1 引入了 rails-ujs,它改变了这些事件处理程序的参数。以下应该工作:
$('#myform').bind('ajax:success', function(event) {
const [_data, _status, xhr] = event.detail;
});
Source:https://edgeguides.rubyonrails.org/working_with_javascript_in_rails.html#rails-ujs-event-handlers
来源:https: //edgeguides.rubyonrails.org/working_with_javascript_in_rails.html#rails-ujs-event-handlers
回答by Franchy
I know this is an old question but someone can benefit from it.
我知道这是一个老问题,但有人可以从中受益。
I think the error is related to this:
我认为错误与此有关:
JS _doit.js.erb $("#my_list").html("<%= escape_javascript(render(:partial => "doit"))%>");
And finally a partial:
_doit.html.erb.
JS _doit.js.erb $("#my_list").html("<%= escape_javascript(render(:partial => "doit"))%>");
最后是部分:
_doit.html.erb。
You are creating a _doit.js.erbpartial to respond to the action doitin the controller but what you need is a viewcalled doit.js.erb(without the underscore). Conceptually, the format.jsin your action will respond to a view with the same name of it with extension js.erb.
您正在创建一个_doit.js.erb部分来响应doit控制器中的操作,但您需要的是一个调用的视图doit.js.erb(不带下划线)。从概念上讲,format.js您的操作中的 将响应具有相同名称并带有扩展名的视图js.erb。

