发表于:2006.05.06 22:37
分类: Rails散文
出处:http://my4java.itpub.net/post/9983/85944
---------------------------------------------------------------
HowtoPagination
A、控制器内的 Pagination 一、简单的 Pagination首先,要看看 Pagination 帮助方法是否适合你的目的。通常它允许 :include,:joins,:conditions,和 :order。事实上,它使用 Model.find(:all,*params)来完成它的工作。这可用于你大多数情况。
“paginate”返回两个东西:一个 Paginator 对象和一个当前页条目的集合。所以它使用双赋值语法(x,y = painate(z))。不要让这困惑你。
这儿是个例子:
def list @item_pages, @items = paginate(:items, :include => [:parent_item], :conditions => ['parent_id = ?', @some_id], :order => 'created_on ASC', :per_page => 20)end当前页由 @params[‘page’] 变量决定。
有关 Pagination 帮助方法更多信息可查阅: http://wiki.rubyonrails.com/rails/pages/PaginationHelper
二、定制 Pagination内建的 Pagination 方法在你的 find 变得复杂时会有限制。如果你使用 find_by_SQL ,那么你将明确地想考虑直接使用 Paginator 。这不比 Pagination 帮助方法复杂并且没有什么值得害怕的。
你将只需要决定被找到条目的总数量,每页数量,和当前页。然后,你可用它们创建一个 Paginator 的实例。
这儿,你也会想做出个选择。你要更有效率,对 findAll匹配记录,统计它们,然后只显示被找到集合的一个页?或者这会更有效率,对数据库做出两个调用:1)一个被匹配记录的 SQL COUNT ,2)只找到当前页显示的记录。第一种途径将只使用你的SQL数据库一次,但我们会得到许多记录。第二个途径将使用你的SQL数据库两次,但每次将只返回一小部分信息。
你必须决定哪种途径适合于你。回答是这依赖于许多因素:你工作的数据库的尺寸,你的服务器的速度,数据库通信量,你的其它SQL调用的效率,你的数据库设计,或者甚至是你的数据库大小。我发现我可以使用第一个途径(找出所有记录)可成功地找出1000个记录—你的英里数在变化。你总是可以用第一种途径开始,并在它变慢时轻易地修改它。
这儿是个 one-SQL-trip,用四种简单的步骤获得所有东西的方法。
def list # 步骤1:读取并设置你需的变量
page = (params[:page] ||= 1).to_i items_per_page = 20 offset = (page - 1) * items_per_page
# 步骤 2:完成你定制find而没有任何种类限制或偏移量
# 也就是,获取每个页的所有东西,不麻烦 pagination 。
@items = Item.find_with_some_custom_method(@some_variable)
# 步骤 3:创建一个 Paginator, 第二个变量持有所有页内的所有条目。
@item_pages = Paginator.new(self, @items.length, items_per_page, page)
# 步骤 4:只发送@items的一个子集给视图
# 这就是魔术开始的地方... 并且你不必完成其它的find
@items = @items[offset..(offset + items_per_page - 1)]
end第二个途径也很容易。你只需要两个SQL方法。在步骤2中,你完成一定数量匹配的记录,然后在步骤4内,你只重新取回当前页的记录。注意,那个”offset”和”items_per_page”将需要与你的模型的定义find方法如 :offset 和 :limit 参数选项合在一起。(查阅Rdoc文档的 find 方法。)
def list # 步骤 1:读取并设置你需要的变量
page = (params[:page] ||= 1).to_i items_per_page = 20 offset = (page - 1) * items_per_page
# 步骤 2: 替代查找全部,只找count个记录
@item_count = Item.find_record_count(@some_variable)
# 步骤 3: 创建一个 Paginator, 第二个变量持有所有页所有条目
@item_pages = Paginator.new(self, @item_count, items_per_page, page)
# 步骤 4: 只查找被请求的 @items 子集
@items =Item.find_with_some_custom_method(@some_variable, offset, items_per_page)end
B、视图内 Pagination 一旦你控制器已经赋值给 @item_pages(一个 Paginator 实例)和 @items (一个活动记录对象的集合),你就可以准备在你的视图中利用它们。与 paginator 对象工作并不困难。唯一的 catch 是确保你的其它参数被保存并发送给下一页。(你将注意到支架的 pagination并不缺省地完成这些。)
一、前一页和下一页链接<%= link_to('previous page', {:params => params.merge('page' => @item_pages.current.previous)}) if @item_pages.current.previous %><%= ' | ' if @item_pages.current.previous and @item_pages.current.next %><%= link_to('next page', {:params => params.merge('page' => @item_pages.current.next)}) if @item_pages.current.next %>二、List of page number linksPages: <% for page in @item_pages -%><%= link_to_unless(params[:page].to_i == page.number, page.number, {:params => params.merge('page' => page)}) %> <% end -%><br />
<!-- Or make the unlinked version bold --><% for page in @item_pages -%> <%= link_to_unless(params[:page].to_i == page.number, page.number, {:params => params.merge('page' => page)}) {|link_name| "<strong>#{link_name}</strong>"} %> <% end -%><br />
<!-- Or give both links and non-links CSS class styles --><% for page in @item_pages -%> <%= link_to_unless(params[:page].to_i == page.number, page.number, {:params => params.merge('page' => page)}, {:class => 'linked_page'}) {|link_name| "<span class="unlinked_page">#{link_name}</span>"} %> <% end -%><br />二、Information about the subset being displayedDisplaying <%= @item_pages.current_page.first_item %> through <%= @item_pages.current_page.last_item %> of <%= @item_pages.item_count %> items.我希望这个 pagination 指南能有帮助。我将试着回答任何问题。
Questions:
- Q: 如果传递当前页给 paginate 而不使用 @params
- A: 页可以用你喜欢的任何Rails方式传递,只要你发现@params不适合于你。Session 变量,cookie变量,和flash变量都是可能的。通过@params通常将更好。
- Q: I don’t like the way paginate handles overflow pages, for example there only 2 pages, I specify page 3, paginate will show page 1 should be page 2
- A: If you don’t like this behavior you can handle it differently in your controller. Just intercept @params[‘page’], test it for whatever criteria you like and modify it’s value as necessary.
- Another @params[‘page’] tidbit. If you want to go back to a specific page, after navigating in your app, here’s how to do that. First, put code to this effect into the controller to store the @params[‘page’] into the session MyController#list def list session[:page] = @params[‘page’] end. Second, to link back to this same page, include this in the view <= link_to ‘Back’, :action => ‘list’,:page => session[:page] > Thanks to plasko, who deserves the credit for this solution. —mattyboy
- Q: How can I populate paginator using find_with_sql() or populate it from an array generated from my own method?
首先,要看看 Pagination 帮助方法是否适合你的目的。通常它允许 :include,:joins,:conditions,和 :order。事实上,它使用 Model.find(:all,*params)来完成它的工作。这可用于你大多数情况。
“paginate”返回两个东西:一个 Paginator 对象和一个当前页条目的集合。所以它使用双赋值语法(x,y = painate(z))。不要让这困惑你。
这儿是个例子:
def list @item_pages, @items = paginate(:items, :include => [:parent_item], :conditions => ['parent_id = ?', @some_id], :order => 'created_on ASC', :per_page => 20)end当前页由 @params[‘page’] 变量决定。
有关 Pagination 帮助方法更多信息可查阅: http://wiki.rubyonrails.com/rails/pages/PaginationHelper
二、定制 Pagination内建的 Pagination 方法在你的 find 变得复杂时会有限制。如果你使用 find_by_SQL ,那么你将明确地想考虑直接使用 Paginator 。这不比 Pagination 帮助方法复杂并且没有什么值得害怕的。
你将只需要决定被找到条目的总数量,每页数量,和当前页。然后,你可用它们创建一个 Paginator 的实例。
这儿,你也会想做出个选择。你要更有效率,对 findAll匹配记录,统计它们,然后只显示被找到集合的一个页?或者这会更有效率,对数据库做出两个调用:1)一个被匹配记录的 SQL COUNT ,2)只找到当前页显示的记录。第一种途径将只使用你的SQL数据库一次,但我们会得到许多记录。第二个途径将使用你的SQL数据库两次,但每次将只返回一小部分信息。
你必须决定哪种途径适合于你。回答是这依赖于许多因素:你工作的数据库的尺寸,你的服务器的速度,数据库通信量,你的其它SQL调用的效率,你的数据库设计,或者甚至是你的数据库大小。我发现我可以使用第一个途径(找出所有记录)可成功地找出1000个记录—你的英里数在变化。你总是可以用第一种途径开始,并在它变慢时轻易地修改它。
这儿是个 one-SQL-trip,用四种简单的步骤获得所有东西的方法。
def list # 步骤1:读取并设置你需的变量
page = (params[:page] ||= 1).to_i items_per_page = 20 offset = (page - 1) * items_per_page
# 步骤 2:完成你定制find而没有任何种类限制或偏移量
# 也就是,获取每个页的所有东西,不麻烦 pagination 。
@items = Item.find_with_some_custom_method(@some_variable)
# 步骤 3:创建一个 Paginator, 第二个变量持有所有页内的所有条目。
@item_pages = Paginator.new(self, @items.length, items_per_page, page)
# 步骤 4:只发送@items的一个子集给视图
# 这就是魔术开始的地方... 并且你不必完成其它的find
@items = @items[offset..(offset + items_per_page - 1)]
end第二个途径也很容易。你只需要两个SQL方法。在步骤2中,你完成一定数量匹配的记录,然后在步骤4内,你只重新取回当前页的记录。注意,那个”offset”和”items_per_page”将需要与你的模型的定义find方法如 :offset 和 :limit 参数选项合在一起。(查阅Rdoc文档的 find 方法。)
def list # 步骤 1:读取并设置你需要的变量
page = (params[:page] ||= 1).to_i items_per_page = 20 offset = (page - 1) * items_per_page
# 步骤 2: 替代查找全部,只找count个记录
@item_count = Item.find_record_count(@some_variable)
# 步骤 3: 创建一个 Paginator, 第二个变量持有所有页所有条目
@item_pages = Paginator.new(self, @item_count, items_per_page, page)
# 步骤 4: 只查找被请求的 @items 子集
@items =Item.find_with_some_custom_method(@some_variable, offset, items_per_page)end
B、视图内 Pagination 一旦你控制器已经赋值给 @item_pages(一个 Paginator 实例)和 @items (一个活动记录对象的集合),你就可以准备在你的视图中利用它们。与 paginator 对象工作并不困难。唯一的 catch 是确保你的其它参数被保存并发送给下一页。(你将注意到支架的 pagination并不缺省地完成这些。)
一、前一页和下一页链接<%= link_to('previous page', {:params => params.merge('page' => @item_pages.current.previous)}) if @item_pages.current.previous %><%= ' | ' if @item_pages.current.previous and @item_pages.current.next %><%= link_to('next page', {:params => params.merge('page' => @item_pages.current.next)}) if @item_pages.current.next %>二、List of page number linksPages: <% for page in @item_pages -%><%= link_to_unless(params[:page].to_i == page.number, page.number, {:params => params.merge('page' => page)}) %> <% end -%><br />
<!-- Or make the unlinked version bold --><% for page in @item_pages -%> <%= link_to_unless(params[:page].to_i == page.number, page.number, {:params => params.merge('page' => page)}) {|link_name| "<strong>#{link_name}</strong>"} %> <% end -%><br />
<!-- Or give both links and non-links CSS class styles --><% for page in @item_pages -%> <%= link_to_unless(params[:page].to_i == page.number, page.number, {:params => params.merge('page' => page)}, {:class => 'linked_page'}) {|link_name| "<span class="unlinked_page">#{link_name}</span>"} %> <% end -%><br />二、Information about the subset being displayedDisplaying <%= @item_pages.current_page.first_item %> through <%= @item_pages.current_page.last_item %> of <%= @item_pages.item_count %> items.我希望这个 pagination 指南能有帮助。我将试着回答任何问题。
Questions:
- Q: 如果传递当前页给 paginate 而不使用 @params
- A: 页可以用你喜欢的任何Rails方式传递,只要你发现@params不适合于你。Session 变量,cookie变量,和flash变量都是可能的。通过@params通常将更好。
- Q: I don’t like the way paginate handles overflow pages, for example there only 2 pages, I specify page 3, paginate will show page 1 should be page 2
- A: If you don’t like this behavior you can handle it differently in your controller. Just intercept @params[‘page’], test it for whatever criteria you like and modify it’s value as necessary.
- Another @params[‘page’] tidbit. If you want to go back to a specific page, after navigating in your app, here’s how to do that. First, put code to this effect into the controller to store the @params[‘page’] into the session MyController#list def list session[:page] = @params[‘page’] end. Second, to link back to this same page, include this in the view <= link_to ‘Back’, :action => ‘list’,:page => session[:page] > Thanks to plasko, who deserves the credit for this solution. —mattyboy
- Q: How can I populate paginator using find_with_sql() or populate it from an array generated from my own method?
一旦你控制器已经赋值给 @item_pages(一个 Paginator 实例)和 @items (一个活动记录对象的集合),你就可以准备在你的视图中利用它们。与 paginator 对象工作并不困难。唯一的 catch 是确保你的其它参数被保存并发送给下一页。(你将注意到支架的 pagination并不缺省地完成这些。)
一、前一页和下一页链接<%= link_to('previous page', {:params => params.merge('page' => @item_pages.current.previous)}) if @item_pages.current.previous %><%= ' | ' if @item_pages.current.previous and @item_pages.current.next %><%= link_to('next page', {:params => params.merge('page' => @item_pages.current.next)}) if @item_pages.current.next %>二、List of page number linksPages: <% for page in @item_pages -%><%= link_to_unless(params[:page].to_i == page.number, page.number, {:params => params.merge('page' => page)}) %> <% end -%><br />
<!-- Or make the unlinked version bold --><% for page in @item_pages -%> <%= link_to_unless(params[:page].to_i == page.number, page.number, {:params => params.merge('page' => page)}) {|link_name| "<strong>#{link_name}</strong>"} %> <% end -%><br />
<!-- Or give both links and non-links CSS class styles --><% for page in @item_pages -%> <%= link_to_unless(params[:page].to_i == page.number, page.number, {:params => params.merge('page' => page)}, {:class => 'linked_page'}) {|link_name| "<span class="unlinked_page">#{link_name}</span>"} %> <% end -%><br />二、Information about the subset being displayedDisplaying <%= @item_pages.current_page.first_item %> through <%= @item_pages.current_page.last_item %> of <%= @item_pages.item_count %> items.我希望这个 pagination 指南能有帮助。我将试着回答任何问题。
Questions:
- Q: 如果传递当前页给 paginate 而不使用 @params
- A: 页可以用你喜欢的任何Rails方式传递,只要你发现@params不适合于你。Session 变量,cookie变量,和flash变量都是可能的。通过@params通常将更好。
- Q: I don’t like the way paginate handles overflow pages, for example there only 2 pages, I specify page 3, paginate will show page 1 should be page 2
- A: If you don’t like this behavior you can handle it differently in your controller. Just intercept @params[‘page’], test it for whatever criteria you like and modify it’s value as necessary.
- Another @params[‘page’] tidbit. If you want to go back to a specific page, after navigating in your app, here’s how to do that. First, put code to this effect into the controller to store the @params[‘page’] into the session MyController#list def list session[:page] = @params[‘page’] end. Second, to link back to this same page, include this in the view <= link_to ‘Back’, :action => ‘list’,:page => session[:page] > Thanks to plasko, who deserves the credit for this solution. —mattyboy
- Q: How can I populate paginator using find_with_sql() or populate it from an array generated from my own method?
Pages: <% for page in @item_pages -%><%= link_to_unless(params[:page].to_i == page.number, page.number, {:params => params.merge('page' => page)}) %> <% end -%><br />
<!-- Or make the unlinked version bold --><% for page in @item_pages -%> <%= link_to_unless(params[:page].to_i == page.number, page.number, {:params => params.merge('page' => page)}) {|link_name| "<strong>#{link_name}</strong>"} %> <% end -%><br />
<!-- Or give both links and non-links CSS class styles --><% for page in @item_pages -%> <%= link_to_unless(params[:page].to_i == page.number, page.number, {:params => params.merge('page' => page)}, {:class => 'linked_page'}) {|link_name| "<span class="unlinked_page">#{link_name}</span>"} %> <% end -%><br />





