3

我试图用 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" alt="cargando..."/></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?

编辑

在控制台中检查响应时,它还显示正在加载要加载的新配方,但视图中没有发生任何事情

任何指针表示赞赏

谢谢

4

5 回答 5

11

为什么不尝试一种更简单的方法,创建一个具有以下内容的新助手(例如 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 参数,因为 will_paginate 使用呈现页面时存在的所有参数创建页面 url,并且我们不想重用 cache buster 参数。

链接方法是原始LinkRenderer 源代码的复制粘贴,但使用 remote: true 创建链接以使其成为 JS 请求。

最后,js_will_paginate方法是一个标准的视图助手方法,用于调用普通的 will_paginate 视图助手方法,但将我们的自定义渲染器添加到选项中,以便使用它来代替普通渲染器。

于 2012-12-20T15:21:52.977 回答
3

以防万一有人正在寻找 Rails 4 解决方案。我喜欢 Pierre Pretorius 的回答,但它在 4.1.1 上对我来说失败了,因为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();"))

我希望它可以帮助某人。

于 2014-06-28T10:53:31.360 回答
2

您没有在 js.erb 中转义 javascript,这应该是问题所在。

$('#userRecipes').html('<%= escape_javascript(render partial: 'userrecipes') %>');
$.setAjaxPagination();
于 2012-12-09T15:28:12.537 回答
1

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”,这样代码就不会混乱。我希望这有帮助

于 2013-02-26T09:46:19.737 回答
1

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,因为助手会处理这些或有一个咖啡脚本文件。

于 2015-07-30T20:40:24.433 回答