`

一个经典的Rails AJAX 搜索 排序 和分页示例

阅读更多
写在前头
     绿色的部分是,这个介绍容易出问题部分的解释。本来就是面向零基础,才写的,所以不怕麻烦和琐碎。然而,如果你还是嫌太麻烦,或者你不希望了解细节的话。那么,我建议你直接点击这里,下载ajaxtable.rar的压缩包。在安装ruby和rails的环境下,到解压的目录下,运行ruby script/server直接看效果。
     压缩包里有paginate的plugin,数据库也不用配置因为是文件的。万一你的系统不认sqlite3,请下载sqlite3的rar,里面有个gem包安装就可以了。
    希望能够给有兴趣的,或者初学者带来帮助


   这是一个相当经典的(我认为^_^)用来展示,ajax调用排序,搜索和分页的示例。这个示例的特点是把过程写的相当的啰嗦,大妈专杀。以至于非常的好理解,非常的初级,非常的好用。

任务说明简介和重要提示

在这个示例教程理,我们将要使用Rails的AJAX,来实现对结果集的如下功能:

1. 分页
2. 排序,可以对结果集的任何一个属性进行ajax排序。
3. 查询,ajax检索

在线的示例演示,请访问如下网址:(还没有准备好...)

能够部分刷新的对页面的结果集进行更新,变得越来越普遍。对于Rails来说,天生的和ajax有着完美的支持。所以,对这项功能的实现相当容易。
示例中的代码, 很大部分来源于Rails Wiki的官方说明。特别是How to make a real-time search box with the Ajax helpers 和 How to paginate with Ajax.我只是把这些代码攒到了一起,不能用的时候,稍微改了一下变量名。以便看起来更不像抄袭。

注意啦,很重要:
我既不是Rails高手,也不是AJAX大拿。在这两个领域里,我都是拥有长期经验的菜鸟。所以这个示例是面对初学者和大妈们的。你会看到简介的代码,详尽的解释,但是缺乏高效规范。幸好,虽然,我的母语是汉语,但是难免还是有错误。
任何时候,请到我的博客告诉我。

应用安装和配置
在这个示例中,我们假设已经安装了当前的Rails环境(至少高于2.0)和支持数据库。在我们这里用Sqlite,当然你也可以很容易的使用其他的数据库代替。

框架生成:
我们要在目录下生成“skeleton”先:
rails ajaxtable
cd ajaxtable


在rails 2.0以后,分页的功能已经从Rails core中分离出来,成为一个独立的plugin叫作classic pagination。很不幸的很多开发者,认为will_paginate是更加流行的分页插件。但是,我并没有使用will_paginate整合我的示例。所以,我们还是首先,使用下面的命令安装classic pagination plugin
ruby script/plugin install svn://errtheblog.com/svn/plugins/classic_pagination

这里如果不能安装,请直接下载附件classic_pagination.rar解压缩放到verdor\plugin目录,就不用安装分页插件了。

鉴于,我们搭建的是一个非常基础的应用,所以,我们只有一个用来存储结果集的model和controller。我们将使用如下Rails的scripts生成
$ ruby script/generate model Item
$ ruby script/generate controller Item


数据库准备:

简单起见,我们选择sqlite做存储。这将意味着我们将描述文件放到Rails中,并且用它生成数据库。
更新数据库配置文件:config/database.yml如下:
development:
  adapter: sqlite3
  database: db/development.db

然后,我们将使用如下Rails migration 工具创建数据库如下:
ruby script/generate migration database_creation


这条语句将生成类似db/migrate/20090303130724_database_creation.rb的文件。
修改这个文件,重新定义数据库表结构
class DatabaseCreation < ActiveRecord::Migration

  def self.up
    create_table :items do |t|
      t.column :name, :string, :limit => 30
      t.column :quantity, :integer, :null => false, :default => 0
      t.column :price,  :integer, :null => false, :default => 0
    end
  end

  def self.down
    drop_table :items
  end

end

然后,运行如下:

rake db:migrate


这里如果,出现不能安装错误请下载附件sqlite3.rar,并放到ruby\bin目录下,执行
gem install -l c:\ruby\bin\sqlite3-ruby-1.2.3-mswin32.gem



用以创建表结构。接下来将加载数据

在db目录下应该有一个development.db的文件,这个文件就是存储sqlite数据。
你可以用如下的方法插入数据创建db/dump.sql如下:

BEGIN TRANSACTION;
INSERT INTO "items" VALUES(1, 'hoe', 3, 10);
INSERT INTO "items" VALUES(2, 'wheelbarrow', 2, 60);
INSERT INTO "items" VALUES(3, 'gherkin', 15, 3);
INSERT INTO "items" VALUES(4, 'batman', 1, 3000);
INSERT INTO "items" VALUES(5, 'fish sausage', 2, 8);
INSERT INTO "items" VALUES(6, 'sauerkraut', 9, 9);
INSERT INTO "items" VALUES(7, 'watering-can', 4, 13);
INSERT INTO "items" VALUES(8, 'dandelions', 78, 1);
INSERT INTO "items" VALUES(9, 'refrigerator', 12, 250);
INSERT INTO "items" VALUES(10, 'flying matches', 8, 145);
INSERT INTO "items" VALUES(11, 'broken accordion', 1, 18);
INSERT INTO "items" VALUES(12, 'savage whisper', 5, 7);
INSERT INTO "items" VALUES(13, 'hysterical snail', 8, 13);
COMMIT;


运行:
sqlite3 db/development.db < db/dump.sql

注意:
1.如果运行这个命令的时候,提示找不到sqlite3,请下载sqlite3的附件,放到ruby\bin\下,并且运行时,请指明路径
2.如果你使用的数据库是mysql请自己修改,insertinto的语句格式如下 INSERT INTO items VALUES (1, 'hoe', 3, 10);
那么,到现在为止,我们准备好了数据库和用到的文件

创建model

就像你应该知道的,Rails程序通常会分为三层。实际上我们已经创建了/models/item.rb文件。并且我们并不需要更改。
那么,看起来,我们的第一步编码工作还不算太困难。

创建view

我们应用将被分成两个部分,一个layout 另外一部分是view和partial。

Layout

Layout是页面模板用来容纳不同的几个views。Layout包含一些不变的元素例如:html的header和footer信息,导航和设计元素等。当然,这些功能完全没有能够在我们的示例中体现。因为,我们只有一个页面,
那么layout应该在app/views/layouts/item.rhtml,其中代码如下:

<html>
<head>
  <title>Ajax table manipulation attempt</title>
  <%= stylesheet_link_tag "style" %>
  <%= javascript_include_tag :defaults %>
</head>
<body>

<div id="content">
<%= @content_for_layout %>
</div>

</body>
</html>


在这段代码中,值得注意的是javascript_include_tag 将加载对应的javascript库,以便Rails可以得到AJAX功能支持。
@content_for_layout 部分,将会被生成的内容代替。

view部分

view将会把controller的结果展示。逻辑部分在一节详述。根据Rails配置原则,我们view将对应item controller的listaction所以我们的view在
app/views/item/list.rhtml.
该文件的内容如下:

 <h1>欢迎使用神奇的 items 列表</h1>

<p>我们的列表是Web2.0的经典产物。</p>

<p>但是请注意,这里可能有太多的bug.</p>

<h2>bug list如下</h2>

<p>
<form name="sform" action="" style="display:inline;">
<label for="item_name">Filter on item name  : </label>
<%= text_field_tag("query", params['query'], :size => 10 ) %>
</form>

<%= image_tag("spinner.gif",
              :align => "absmiddle",
              :border => 0,
              :id => "spinner",
              :style =>"display: none;" ) %>
</p>

<%= observe_field 'query',  :frequency => 2,
         :update => 'table',
         :before => "Element.show('spinner')",
         :success => "Element.hide('spinner')",
         :url => {:action => 'list'},
         :with => 'query' %>

<div id="table">
<%= render :partial => "items_list" %>
</div>


开始部分并没有什么复杂的,首先,是一段大妈专用的说明和一个检索输入框用以Filter。

然后,我们有一个id是spinner的隐藏image元素。这个image是用来AJAX有延迟调用的时候显示的(flash加载的滚动条)。当ajax的异步调用完成,可以显示数据时,这个image将再次隐藏。你可以从如下的网站得到更多的类似图片:
http://mentalized.net/activity-indicators/
从上面的网站中下载一个gif,并重命名为spinner.gif放到public/images下。

在接下来的observe_field代码部分是最常用的AJAX代码。它的含义大概是定期检查指定区域的内容,并且当内容有变化的时候响应。

其中,使用到的变量有如下含义:
update 参数描述将要更新的<div>或<span>的id
url    该参数,指定响应和处理action。就是定期触发什么方法。
with   该参数,用以给url中指定的action,传递参数。在这里我们将会把observed field的检索数据传给list action
before 该方法用以指定,当AJAX的异步调用处理中将怎么执行。
sucess 当ajax的异步调用成功后,执行什么操作。

实际的操作流程相当简单,当用户在queryfield的检索框内输入要查询的东西,observerd 就会检测到监视区域的内容变化,然后,生成AJAX的请求,异步调用通过url和with的发送给服务器。注意这时页面是整体和局部都不刷新的。当请求发送的时候,before定义的操作将被执行。在我们的示例中是显示spinner图片。当请求有回复的时候,sucess的操作将被执行,在我们这里是隐藏图片。

实际上,observe_field方面发送的请求参数如下:

<script type="text/javascript">
//<![CDATA[
new Form.Element.Observer('query', 2, function(element, value) {Element.show('spinner'); new Ajax.Updater('table', '/item/list', {asynchronous:true, evalScripts:true, onSuccess:function(request){Element.hide('spinner')}, parameters:'query=' + value})})
//]]>
</script>


我们花时间来看,没一个参数选项的具体含义,是因为我们很快会再用到这些几乎每一种ajax调用都要用到的参数,

创建controller

我们的controller应该可以根据请求类别和参数的不同处理多种的请求。
Item contoller将会非常简单,我们只实现一个list的action。其他CRUD(创建、读取、更新、删除)方法将不在本示例中展示

那么,controller的内容如下:
修改\ajaxtable\app\controllers\item_controller.rb

class ItemController < ApplicationController

  def list

    items_per_page = 10

    sort = case params['sort']
           when "name"  then "name"
           when "qty"   then "quantity"
           when "price" then "price"
           when "name_reverse"  then "name DESC"
           when "qty_reverse"   then "quantity DESC"
           when "price_reverse" then "price DESC"
           end

    conditions = ["name LIKE ?", "%#{params[:query]}%"] unless params[:query].nil?

    @total = Item.count(:conditions => conditions)
    @items_pages, @items = paginate :items, :order => sort, :conditions => conditions, :per_page => items_per_page

    if request.xml_http_request?
      render :partial => "items_list", :layout => false
    end

  end

end


本段代码的简单说明如下:

controller的唯一一个方法,用于处理各种不同请求。其中,items_per_page 参数用以定义每页显示数量。sort参数取决于同名的传入参数。出于安全考虑以此代替真正的字段名。sort 中的reverse参数用于保证再次点击的时候可以依序排列。
conditions 参数用来指定从query请求参数提供的检索条件。这个参数是类似SQL样式。
然后,我们指定@total变量用来存储符合conditions条件的记录个数。

最终,我们调用Rails的分页机制。我们需要关联分页到数据库:item,和一个可排序字段,一个符合conditions的检索条件,和一个每页的显示个数。分页机制就会返回,一个@items_pages 的对象用以分页显示。

Rails和Ajax使用XmlHttpRequest,这不同与普通的GET和POST请求。XHR的请求由javascript通过后台的Http调用触发,请求一个部分的Xhtml代码片段来更新部分的浏览器显示。这样的好处是不用重新加载整个页面。用户的使用体验,会因此变快。

那么接下来呢?

创建partial

partial是用来显示部分的页面。partial的设计初衷是为了复用,满足DRY(Don‘t Repeat Yoursel)的原则,当然,这里对于AJAX也非常有用。

这里我们使用partial更新部分页面,正好满足AJAX部分更新的要求。
Partial文件的名字总是下划线开头。我们的partialapp/views/item/_items_list.rhtml,内容如下

<% if @total == 0 %>

<p>No items found...</p>

<% else %>

<p>Number of items found : <b><%= @total %></b></p>

<p>
<% if @items_pages.page_count > 1 %>
Page&nbsp;:
<%= pagination_links_remote @items_pages %>
<% end %>
</p>


<table>
  <thead>
    <tr>
      <td <%= sort_td_class_helper "name" %>>
        <%= sort_link_helper "Name", "name" %>
      </td>
      <td <%= sort_td_class_helper "qty" %>>
        <%= sort_link_helper "Quantity", "qty" %>
      </td>
      <td <%= sort_td_class_helper "price" %>>
        <%= sort_link_helper "Price", "price" %>
      </td>
    </tr>
  </thead>
  <tbody>
    <% @items.each do |i| %>
    <tr class="<%= cycle("even","odd") %>">
      <td><%= i.name %></td>
      <td><%= i.quantity %></td>
      <td><%= i.price %></td>
    </tr>
    <% end %>
  </tbody>
</table>

<% end %>


分页的helpers文件

在开始的时候,我们有一个符合条件的记录数和设定的每页显示记录数的判断。如果,符合条件的记录数小于每页可以显示的记录数,则不用分页。
相反,我们就需要要显示分页信息,虽然,Rails已经有了处理和显示的机制。可是我们希望能够实现ajax分页。那么我们需要创建pagination的helpers。
helper方法是用来帮助生成和显示view的。目的是为了将显示和逻辑分离,当然一定程度的复用和代码重构。
我们的helper文件在app/helpers/item_helper.rb. 我们的view可以读取这个文件的任何一个方法。但是,如果我们如果,希望应用中的任何view都可以使用这个文件的方法,那么我们就需要把代码放到application_helper.rb.
内容如下:

def pagination_links_remote(paginator)
  page_options = {:window_size => 1}
  pagination_links_each(paginator, page_options) do |n|
    options = {
      :url => {:action => 'list', :params => params.merge({:page => n})},
      :update => 'table',
      :before => "Element.show('spinner')",
      :success => "Element.hide('spinner')"
    }
    html_options = {:href => url_for(:action => 'list', :params => params.merge({:page => n}))}
    link_to_remote(n.to_s, options, html_options)
  end
end

我们定义只有一个window_size的page_options的hash。这个参数标识当前页旁边的可以显示的页,如下如果window_size=1那么就会显示如下:
1 ... 5 6 7 ... 13
如果 window_size=2则显示
1 ... 4 5 6 7 8 ... 13

这样,我们就可以通过pagination_links得到对应的xhtml分页后的xhtml通过以上的连接。这的确可以用,然而,我们希望能够异步调用,实现AJAX的分页,所以我们重写pagination_links_each 方法
pagination_links_each 方法参数分析:
option和类似之前我们observe_field的参数,新的部分是params.merge,表示我们通过连接把将当前的请求参数代替之前的状态。
html_options是用来定义没有AJAX支持下的分页显示。以便分页机制在没有javascript支持下也可以用。

下面是实际的有两个页面市,第一个页面显示时的生成代码

<a href="/item/list?page=2" onclick="Element.show('spinner'); new Ajax.Updater('table', '/item/list?page=2', {asynchronous:true, evalScripts:true, onSuccess:function(request){Element.hide('spinner')}}); return false;">2</a>

sorting helpers

继续添加helpers

sort_td_class_helper代码如下:

def sort_td_class_helper(param)
  result = 'class="sortup"' if params[:sort] == param
  result = 'class="sortdown"' if params[:sort] == param + "_reverse"
  return result
end

作用是添加一个class="sortup"用以支持逆序排列

sort_link_helper.

def sort_link_helper(text, param)
  key = param
  key += "_reverse" if params[:sort] == param
  options = {
      :url => {:action => 'list', :params => params.merge({:sort => key, :page => nil})},
      :update => 'table',
      :before => "Element.show('spinner')",
      :success => "Element.hide('spinner')"
  }
  html_options = {
    :title => "Sort by this field",
    :href => url_for(:action => 'list', :params => params.merge({:sort => key, :page => nil}))
  }
  link_to_remote(text, options, html_options)
end


这个helper是上面pagination_links_remote的缩小版,它有两个参数:
text 用于显示字段的头和排序连接
param 和字段关联的请求参数
本段代码首先定义一个变量key用于保持param传递过来的参数。_reverse用于表示param是否正在排序中的参数。也就是说实现,第二次点击逆序。

接下来的代码定义了link_to_remote方法需要的参数,和paginateion_links_remote非常类似
option是哈希表,详情见上
html_options 也还是为了javascripte不支持下的功能实现。
下面是sort_link_helper以Quantity" 和 "qty" 作为 text 和 param 参数返回值的显示表格

最后,在用patial显示table的时候,如果希望能够,一行一个颜色,我们需要加入一个cycle的rails方法,来自动增加奇数和偶数的样式方法。

最后了

我们已经或多或少的看了,在这个演示中用到的所有技术细节。在这个过程的最后,通过如下url享用你的劳动成果。
如果,这个文档对你有那么半点帮助,我的时间就值得欣慰了。我再重复一下,有什么问题请在我的博客反馈。
谢谢


   
分享到:
评论
1 楼 zhaoningbo 2012-09-29  
非常感谢!正在找上手的例子,果断详细又明确!这个顶,必须有~~~~

相关推荐

    jquery分页,无刷新,AJAX,排序,分页,查找

    在IT行业中,前端开发是至关重要的一环,而jQuery作为一个强大的JavaScript库,极大地简化了DOM操作、事件处理和动画效果。本篇文章将详细讲解如何利用jQuery实现无刷新分页、AJAX数据加载、排序以及查找功能。 一...

    一个ajax分页的公共类

    这个“一个ajax分页的公共类”提供了一个通用的解决方案,可以被多个页面或项目复用,减少了重复代码,提高了开发效率。 1. **Ajax基础** Ajax的核心是通过JavaScript创建XMLHttpRequest对象,向服务器发送异步...

    利用Ajax技术实现分页

    3. 搜索和排序:结合搜索框和排序功能,动态调整分页请求的参数。 4. 无刷新分页样式:通过CSS和JavaScript实现分页按钮的激活、禁用状态,以及当前页的高亮效果。 总结,Ajax技术为实现网页分页提供了便利,通过...

    jquery动态表格数据分页搜索排序代码.zip

    本示例项目"jquery动态表格数据分页搜索排序代码.zip"提供了使用jQuery实现动态表格数据展示、分页、搜索及排序的功能。下面将详细阐述这些功能的实现原理和步骤。 1. **动态表格数据**: 在网页上动态生成表格...

    jquery.tablesorter.js +排序、分页、ajax demo

    首先,tablesorter是一个强大的jQuery插件,由Christian Bach开发,主要用于表格的排序功能。通过简单的几行代码,即可使静态表格具备点击表头进行升序或降序排序的能力。在"jquery.tablesorter.js"中,主要包含了对...

    php ajax mysql 点击加载更多 分页

    6. "ajaxDataList":这个文件可能是一个示例或者模板,用于展示如何使用AJAX获取数据。在实际应用中,它可能是一个JavaScript函数,通过调用XMLHttpRequest对象或使用jQuery等库来发送AJAX请求,并处理返回的数据,...

    dwz .net 简单分页 表头排序、查询

    3. **查询**:查询功能通常包括一个搜索框,用户输入关键词后,前端将关键词发送到后端,后端在数据库中匹配并返回结果。DWZ.NET有内置的“searchForm”组件,可以方便地创建查询表单和处理查询事件。 以上内容涵盖...

    JQuery+Ajax实现数据查询、排序和分页功能

    - 文档中的HTML结构展示了一个表单(form)的使用示例,表单中包含了用于提交分页索引和排序字段的隐藏input元素。 - 表单内部是一个表格(table),其中包含了需要显示的数据和用于输入查询条件的元素。 通过对...

    jquery 无刷新分页排序

    4. **示例数据**:可能是一个北风(Northwind)数据库的子集,用于演示分页和排序功能。 通过这个代码实例,开发者可以学习如何在自己的项目中实现类似的功能,提高用户界面的响应速度和用户体验。同时,也可以根据...

    JQuery,ajax,hibernate+spring,分页查询.rar

    在`描述`中提到的“利用JQuery方便实现基于Ajax的数据查询、排序和分页功能”,意味着JQuery提供了便捷的方法来更新页面内容而无需刷新整个页面,通过Ajax与服务器进行异步通信。`Ajax`(Asynchronous JavaScript ...

    ajax分页和其他ajax小功能

    `TableAjax`很可能是一个与表格相关的Ajax功能示例或代码库,可能包含了实现上述功能的JavaScript代码、HTML模板以及CSS样式。它可能提供了分页的实现方式,以及如何与其他Ajax功能结合使用,如搜索、排序等。通过...

    一款灵活的jQuery插件支持排序、分页.zip

    另一个文件“132692118785810206”,由于没有明确的扩展名,可能是插件的源代码文件、示例文件或者是数据文件,具体用途需要打开查看才能确定。 在实际应用中,这样的jQuery插件通常会通过引入jQuery库和插件脚本,...

    bootstrap table ajax 示例

    在这个“bootstrap table ajax 示例”中,我们看到一个利用 Maven 构建的项目,它展示了如何通过 AJAX 从后台动态地分页获取并显示数据。 首先,我们需要理解Maven。Maven 是一个Java项目管理工具,它帮助开发者...

    分页表格示例

    总的来说,"分页表格示例"是一个关于如何利用jQuery和相关工具实现动态分页和排序功能的教学案例。理解并掌握这些技术对于任何需要处理大量数据的Web开发者来说都至关重要,它提高了网页的响应速度,优化了用户体验...

    Jquery Ajax 存储过程分页

    本示例将详细讲解如何利用jQuery AJAX技术与ASP.NET结合,通过存储过程实现分页功能。 首先,jQuery是JavaScript的一个库,它简化了DOM操作、事件处理、动画以及Ajax交互等任务。AJAX(异步JavaScript和XML)则允许...

    jQuery实现可分页、排序和搜索的表格插件.zip

    本资源"jQuery实现可分页、排序和搜索的表格插件.zip"提供了一个功能强大的jQuery插件,用于创建具有分页、排序和搜索功能的数据表格。这对于网页开发人员来说是非常有用的,特别是那些需要处理大量数据并希望提高...

    Sigma Grid实现ajax动态表格(支持分页、列宽拖动、数据排序).zip

    在实际项目中,这可能是一个包含示例代码或者配置信息的文件,用于演示如何实现Ajax动态加载、分页、列宽拖动和数据排序等功能。 在实际开发中,使用 Sigma Grid 可以大大提高前端数据展示的效率和灵活性。理解并...

    ThinkPHP5.1+Ajax实现的无刷新分页功能示例

    总的来说,通过ThinkPHP5.1和Ajax的结合,我们可以创建一个高效的无刷新分页系统,它不仅能提供流畅的用户体验,还能降低服务器压力。记住,良好的前端设计和优化是提高网站性能的关键,而无刷新分页是这一目标的...

    使用bootstrap-paginator.js 分页来进行ajax 异步分页请求示例

    Bootstrap-paginator.js是一个基于Bootstrap的分页组件,它允许开发者以很小的配置实现分页功能。它广泛应用于需要异步加载数据的场景中,能够高效地显示分页链接,同时支持多种交互方式,例如点击分页链接后,可以...

Global site tag (gtag.js) - Google Analytics