Faster Pagination in Rails

简介:
Faster Pagination in Rails
 
Pagination in Rails has recently surfaced as a hot topic thanks to Kevin Clark's " Thing's you shouldn't be doing in Rails". There seems to be a lot of confusion around the whole issue, no one has offered a definitive reason as to why the default Pagination helpers shouldn't be used, and at the same time there seems to be a consensus among the 'in' people that you should roll your own pagination in your apps. So what's wrong with the default pagination code?
Well, on first look, not much. If you use it correctly Rails will in fact limit your database queries to correct sizes and pages, so no database overhead here. What about the pagination helper itself? Window code? Yes, there does seem to be a problem here! Rails will by default instantiate a number of 'Page' classes and Window classes once you start using the more advanced features of the helper. Now, instantiating 100+ objects for generating 5 links is never a good idea, ok, point taken. But, I think the biggest problem is in fact not the helpers themselves but how the developers use the code. Some will retrieve an entire collection (find all) and then pass it to the paginator to extract the right collection (think paginate_collection), now we are incurring a double overhead - the database query and the additional load on generating the classes. In retrospect, it seems that the helpers are just too powerful, they make it to easy too write inefficient code, and as such it's not that they should be avoided, they should be understood!
Now, how do we solve the problem? Well, an elegant solution is to use something like:  paginating_find. It's a drop-in plugin which will overwrite your default find method  if  you specify the page parameters in your find query. Now, the database side is taken care of, what about the presentation, after all some of those helpers were there for a good reason! Here is a quick extension/helper I came up with to replace the  pagination_links_each to work with paginating_find:
-----------------------------------------------------------------------------
def windowed_pagination_links (pagingEnum, options )
    link_to_current_page = options [ :link_to_current_page ]
    always_show_anchors = options [ :always_show_anchors ]
    padding = options [ :window_size ]
 
    current_page = pagingEnum. page
    html =  ''
 
     #Calculate the window start and end pages 
    padding = padding <  0 ?  0 : padding
    first = pagingEnum. page_exists? (current_page  - padding ) ? current_page - padding :  1
    last = pagingEnum. page_exists? (current_page + padding ) ? current_page + padding : pagingEnum. last_page
 
     # Print start page if anchors are enabled
    html <<  yield ( 1 )  if always_show_anchors  and  not first ==  1
 
     # Print window pages
    first. upto (last )  do |page|
       (current_page == page && !link_to_current_page ) ? html << page : html <<  yield (page )
     end
 
     # Print end page if anchors are enabled
    html <<  yield (pagingEnum. last_page )  if always_show_anchors  and  not last == pagingEnum. last_page
    html
   end
 
It takes the Enum produced by paginating_find and via some simple math (no extra classes instantiated here!) returns control to your block for each link in your window. Ex: 1 ... 5 6 7 8 9 ... 20 - would be produced for page 7 with a window size 2 and anchors (1 and 20) enabled. Here is my  shared/_paginate.rhtml template:
 
-----------------------------------------------------------------------------
<% if collection.page_count != collection.first_page -%>
<div class="pagination">
   <ul>
   <% if collection.previous_page? -%>
          <li class="nextpage">
         <%= link_to '&#171; previous'{ :page => collection.previous_page } %>
     </li>
   <% else -%>
          <li class="disablepage"> &#171; previous </li>
   <% end -%>
 
     <% last_page = 0 -%>
     <% windowed_pagination_links(collection, :window_size => 2, :link_to_current_page => true, :always_show_anchors => true) do |n| -%>
        <% if collection.page == n -%>
             <li class="currentpage"> <%= n %> </li>
        <% else -%>
           <li> <%= "..." if last_page+1 < n %>
            <%= link_to n, :id => params[:id], :page => n %>
           </li>
        <% end -%>
       <% last_page = n -%>
   <% end -%>
 
     <% if collection.next_page? -%>
      <li class="nextpage">
         <%=  link_to 'next &#187;'{ :page => collection.next_page } %>
      </li>
     <% else -%>
       <li class="disablepage"> &#171; next </li>
     <% end -%>
   </ul>
</div>
<% end -%>
Now, add some  css magic and we get:
Pretty (excuse my doodles, I need to configure my tablet), fast and efficient.




本文转自 fsjoy1983 51CTO博客,原文链接:http://blog.51cto.com/fsjoy/94774,如需转载请自行联系原作者
目录
相关文章
|
编解码 监控 网络协议
Android平台GB28181设备接入侧如何实现按需打开视音频采集传输
Android平台GB28181设备接入侧如何实现按需打开视音频采集传输
269 2
|
缓存 JavaScript
vue中使用setInterval()循环定时器的注意事项
vue中使用setInterval()循环定时器的注意事项
522 0
|
存储 容器
信号驱动IO异步IO的对比理解刨析, epoll地ET,LT
信号驱动IO异步IO的对比理解刨析, epoll地ET,LT
信号驱动IO异步IO的对比理解刨析, epoll地ET,LT
|
XML 存储 缓存
架构之:REST和RESTful
架构之:REST和RESTful
|
分布式计算 监控 Kubernetes
实时 OLAP, 从 0 到 1
BTC.com 团队在实时 OLAP 方面的技术演进过程及生产优化实践。
实时 OLAP, 从 0 到 1
|
关系型数据库 MySQL 数据库
django models进行数据库增删查改
django models进行数据库增删查改
|
大数据
互联网广告的进化之路-技术篇【计算广告】
根据行业第三方调研机构发布的2014年互联网广告行业的实力分布数据显示,BAT三家占据了互联网广告的绝对领先地位,毫无疑问,这是一个数据决定一切的时代。如同人类从农耕时代发展到互联网时代,互联网广告的演化过程同样一波三折。
1384 0
|
8天前
|
人工智能 运维 安全
|
6天前
|
人工智能 异构计算
敬请锁定《C位面对面》,洞察通用计算如何在AI时代持续赋能企业创新,助力业务发展!
敬请锁定《C位面对面》,洞察通用计算如何在AI时代持续赋能企业创新,助力业务发展!