使用 will_paginate gem 在 Rails 3.2.3 中调用 Ajax
Posted
技术标签:
【中文标题】使用 will_paginate gem 在 Rails 3.2.3 中调用 Ajax【英文标题】:Ajax call in rails 3.2.3 with will_paginate gem 【发布时间】:2012-11-27 01:38:26 【问题描述】:我正在尝试使用 will_paginate gem 实现 Ajax 调用,我发现本指南 http://ramblinglabs.com/blog/2011/11/rails-3-1-will_paginate-and-ajax 似乎是一个简单的解决方案,虽然它包含我不熟悉的咖啡脚本,所以如果有人有不同的解决方案,请告知..
我的代码如下
我的观点
<div class="container">
<div class="row">
<div id="userRecipes">
<%= render partial: 'userrecipes' %>
</div>
</div><!--/row-->
我的部分(用户食谱)
<% @recipes.each do |r| %>
<div class="span3">
<div class="thumbnail">
<%= image_tag r.avatar.url(:myrecipes) %>
</div>
<h4><%= link_to r.dish_name, r %></h4>
<hr>
<p><%= truncate r.description, :length => 90 %></p>
<p><%= link_to "Edit Recipe", edit_recipe_path(r.id) %></p>
<p><%= link_to "Delete Recipe", recipe_path(r.id), :confirm => "Are you sure?", :method => :delete %></p>
<p><%= link_to "Add to favorites", :controller => 'favourites', :action => 'create', :recipe_id => r.id, :method => :post %></p>
</div><!--/span3-->
<% end %>
<%= will_paginate @recipes %>
更新了 userrecipes.js.erb 文件
$('#userRecipes').html('<%= escape_javascript(render partial: 'userrecipes') %>');
$.setAjaxPagination();
咖啡脚本
$ ->
$.setAjaxPagination = ->
$('.pagination a').click (event) ->
event.preventDefault()
loading = $ '<div id="loading" style="display: none;"><span><img src="/assets/loading.gif" /></span></div>'
$('.other_images').prepend loading
loading.fadeIn()
$.ajax type: 'GET', url: $(@).attr('href'), dataType: 'script', success: (-> loading.fadeOut -> loading.remove())
false
$.setAjaxPagination()
当我单击下一个锚标记以显示下一组结果时,页面保持原样并且不会出现新内容
当使用控制台查看是否有任何错误我可以看到任何错误时,输出是
GET http://localhost:3000/my_recipes?page=2&_=1355055997639
我在这里错过了什么吗?还是我的 userrecipes.js.erb 文件有问题,因为在其他 Ajax 示例中我看到你在渲染部分时使用了 escape_javascript?
编辑
在控制台中检查响应时,它还显示正在加载要加载的新配方,但视图中没有发生任何事情
欢迎指点
谢谢
【问题讨论】:
你能用 firebug 等追踪来自浏览器的请求吗...响应中的内容是什么? 我的回复显示下一组食谱正在按照我的要求显示,但视图没有显示? 【参考方案1】:您没有在 js.erb 中转义 javascript,这应该是问题所在。
$('#userRecipes').html('<%= escape_javascript(render partial: 'userrecipes') %>');
$.setAjaxPagination();
【讨论】:
不幸的是,这不起作用,做同样的事情,尽管到目前为止感谢您的帮助。还有其他的吗? 谢谢,这就是我所期待的,一个解决我问题的代码。非常感谢@emrah,这种偿付能力甚至可以在不使用on
或live
(旧的JQuery)的情况下使用,而是使用click
。但还是使用on
更好:) 太棒了【参考方案2】:
为什么不尝试一种更简单的方法,创建一个具有以下内容的新助手(例如 app/helpers/will_paginate_helper.rb):
module WillPaginateHelper
class WillPaginateJSLinkRenderer < WillPaginate::ActionView::LinkRenderer
def prepare(collection, options, template)
options[:params] ||=
options[:params]['_'] = nil
super(collection, options, template)
end
protected
def link(text, target, attributes = )
if target.is_a? Fixnum
attributes[:rel] = rel_value(target)
target = url(target)
end
@template.link_to(target, attributes.merge(remote: true)) do
text.to_s.html_safe
end
end
end
def js_will_paginate(collection, options = )
will_paginate(collection, options.merge(:renderer => WillPaginateHelper::WillPaginateJSLinkRenderer))
end
end
那么在你看来,使用这个标签进行 ajax 分页:
<%= js_will_paginate @recipes %>
请记住,分页链接将包含 url 的现有参数,您可以排除这些,如下所示。这是标准的分页功能:
<%= js_will_paginate @recipes, :params => :my_excluded_param => nil %>
希望能解决您的问题。
说明:
Will_paginate 允许您创建自己的自定义渲染器。 WillPaginateJSLinkRenderer 就是这样一个自定义渲染器,这个类可以在任何地方定义,它不必在辅助模块中定义。自定义渲染器扩展了标准渲染器(LinkRenderer),只重新定义了两个方法。
prepare 方法 被重写以显式删除cache buster parameter,因为 will_paginate 使用呈现页面时存在的所有参数创建页面 url,并且我们不想重用缓存破坏器参数。
link 方法 是从原始LinkRenderer source code 复制粘贴,但会创建一个带有 remote: true 的链接以使其成为 JS 请求。
最后,js_will_paginate 方法是一个标准的视图助手方法,用于调用普通的 will_paginate 视图助手方法,但将我们的自定义渲染器添加到选项中,以便使用它来代替普通的渲染器。
【讨论】:
谢谢你的回答,虽然我什么都不懂..请问你是否可以编辑答案并放入一些 cmets 来解释发生了什么是不是太过分了? 在解决方案下方添加了说明。你在你的应用中试过了吗? 获取uninitialized constant WillPaginate::ActionView
请帮助我收到此错误ActionView::Template::Error (undefined method total_pages for #<Position::ActiveRecord_Relation:0x55681e0>)
我收到了响应,但没有绑定到 div【参考方案3】:
ajax_will_paginate 是一个极好的方法,但不幸的是它弄乱了分页的 UI。我采用了另一种 javascript 方法以获得更大的灵活性。我在 pageRender 上调用了这个方法。
function checkForAjaxPaginate(controller,make_ajax)
var href = "";
$(".pagination").find("ul").each(function()
$(this).find("li").each(function()
$(this).find("a").each(function()
href = $(this).attr("href");
if(href.indexOf(controller+".js") != -1)
if(make_ajax)
$(this).attr("data-remote","true");
else
$(this).attr("href",href.replace(".js",""));
);
);
);
为了获得更大的灵活性,您只需在“控制器”变量中传递动作名称,如果要将其转换为 ajax,则将 true 传递给 make_ajax。我所做的只是检查href链接是否为“.js”,如果make_ajax为真,然后添加一个attr“data-remote = true”,在我们的ROR应用程序中使其成为ajax。如果 make_ajax 不正确,那么我只是删除“.js”,这样代码就不会混乱。 我希望这会有所帮助
【讨论】:
【参考方案4】:以防万一有人在寻找 Rails 4 解决方案。我喜欢 Pierre Pretorius 的回答,但它在 4.1.1 上对我来说失败了,"method undefined" for link_to_function 上线了:
@template.link_to_function(text.to_s.html_safe, ajax_call, attributes)
我刚刚将行替换为:
@template.link_to(text.to_s.html_safe, '#', attributes.merge(:onclick => "#ajax_call event.preventDefault();"))
我希望它可以帮助某人。
【讨论】:
【参考方案5】:Pierre Pretorius 的回答很棒,但我必须做更多的工作才能使它对我有用,这还不清楚。也许这对其他初学者会有帮助。
除了制作那个助手和使用js_will_paginate
标签之外,我还这样做了:
在将我试图分页的内容移动到部分内容后(在上面的例子中为_recipes.html.erb
),我还创建了一个show.js.erb
文件(在与部分内容相同的视图中),其文本类似于:
$('#recipes').html('<%= escape_javascript(render partial: 'recipes') %>');
然后我必须将 js_will_paginate 标记也移动到底部的部分(因此它会在我分页或单击下一个/上一个时更新)。然后我必须将渲染部分帮助程序包装在您在 js 文件中定位的 div id 中,所以在这个例子中:
<div id="recipes">
<%= render partial: "recipes" %>
</div>
这对其他人来说可能很清楚,但我不确定 OP 中的哪些步骤必须保留,哪些是不必要的。这些步骤对我有用。你不需要在控制器中添加 respond_to js,因为助手会处理这个或有一个咖啡脚本文件。
【讨论】:
以上是关于使用 will_paginate gem 在 Rails 3.2.3 中调用 Ajax的主要内容,如果未能解决你的问题,请参考以下文章
ruby will_paginate(3.0.7)自定义渲染器。注释掉的代码是此版本gem的默认代码。使用`super`作为写的贝尔
在 Rails 中使用 will_paginate 和 AJAX 实时搜索和 jQuery