Ruby on Rails将对数组进行分页


72

我想知道是否有人可以解释如何使用 在对象数组上will_paginate

例如,在我的网站上,我有一个意见栏,用户可以在其中对意见进行评分。这是我写的一种方法,用于收集对该意见进行评级的用户:

def agree_list
  list = OpinionRating.find_all_by_opinion_id(params[:id])
  @agree_list = []
  list.each do |r|
    user = Profile.find(r.profile_id)
    @agree_list << user
  end
end

谢谢


1
从Google搜索“ rails paginate array”来到这里之后,我想与其他访问者分享kaminari是我所选择的rails pagination的替代方案。优雅地处理数组。
Tod Birdsall

Answers:


218

will_paginate 3.0旨在利用ActiveRecord::RelationRails 3中的新功能,因此paginate默认情况下它仅在关系上定义。它仍然可以与数组一起使用,但是您必须告诉rails需要该部分。

在您config/initializers(我用过的will_paginate_array_fix.rb)的文件中,添加此

require 'will_paginate/array'

然后可以在数组上使用

my_array.paginate(:page => x, :per_page => y)

这有所帮助,但无法在视图中正确显示分页。
Robbie Guilfoyle 2013年

4
有人可以告诉我-我们将如何渲染它?--- @array = my_array.paginate(:页=>的x,:per_page => Y)<%= will_paginate @阵列%>
哈拉

1
@Robbie Guilfoyle my_array.paginate(:page => params [:page],:per_page => 1)这对我来说是固定的分页:)
ConorB

9

您可以Array#from用来模拟分页,但是真正的问题在于您根本不应该使用Array

这就是ActiveRecord关联的用途。您应该仔细阅读该指南,如果您正在开发Rails应用程序,则需要了解很多有用的东西。

让我向您展示做同一件事的更好方法:

class Profile < ActiveRecord::Base
  has_many :opinion_ratings
  has_many :opinions, :through => :opinion_ratings
end

class Opinion < ActiveRecord::Base
  has_many :opinion_ratings
end

class OpinionRating < ActiveRecord::Base
  belongs_to :opinion
  belongs_to :profile
end

重要的是您的数据库架构要遵循正确的命名约定,否则所有这些都将破坏。确保您正在使用数据库迁移创建表来而不要手工完成。

这些关联将在您的模型上创建帮助器,以使搜索更加容易。您可以使Rails使用named_scopescope取决于您使用的是Rails 2.3还是3.0,而不是迭代OpinionRatings列表并手动收集用户,而无需使用Rails 2.3或3.0。由于您未指定,因此我将给出两个示例。将此添加到您的OpinionRating类:

2.3

named_scope :for, lambda {|id| 
  {
    :joins => :opinion,
    :conditions => {
      :opinion => { :id => id }
    }
  }
}

named_scope :agreed, :conditions => { :agree => true }
named_scope :with_profiles, :includes => :profile

3.0

scope :agreed, where(:agree => true)

def self.for(id)
  joins(:opinion).where(:opinion => { :id => id })
end

在这两种情况下,你可以调用for(id)OpinionRatings模型,并把它传递一个id:

2.3

@ratings = OpinionRating.agreed.for(params[:id]).with_profiles
@profiles = @ratings.collect(&:profile)

3.0

@ratings = OpinionRating.agreed.for(params[:id]).includes(:profile)
@profiles = @ratings.collect(&:profile)

所有这些的结果是,您现在可以轻松地分页:

@ratings = @ratings.paginate(:page => params[:page])

Rails 4.x的更新:大致相同:

scope :agreed, ->{ where agreed: true }

def self.for(id)
  joins(:opinion).where(opinion: { id: id })
end 

尽管对于较新的Rails,我更喜欢分页的kaminari

@ratings = @ratings.page(params[:page])

好吧,关联是表Opinion has_many:opinion_ratings表和belongs_to:opinion表。通过与联接表(称为“类别”)的多对多关系,概要文件表获得了意见。通过此设置,您知道它如何更改您上面提到的代码吗?
布赖恩2010年

@Brian我已经更新了示例,但是除非您向我展示了模型类,否则我无法确定。
亚当·拉瑟克

亚当,我如何看待意见评估模型?如果我正确理解Profile.with_opinion,则返回具有指定ID的所有配置文件的列表?我需要的是从OpinionRating模型中获取配置文件列表,该模型属于Emirates_to:opinion和Opinion has_many:opinion_ratings。“个人档案”模型通过“类别”联接表链接到“意见”模型。
Brian

这就是为什么我使用数组的原因,因为我不确定如何查询数据库。
布莱恩(Brian)2010年

好吧,我感谢您的帮助,但是我想我找到了问题的答案。不知道这是否是最有效的方法,但它是否有效。我将进一步研究named_scope并尝试在将来实现。
布赖恩2010年

4

gemwill_paginate将对ActiveRecord查询和数组进行分页。

list = OpinionRating.where(:opinion_id => params[:id]).includes(:profile).paginate(:page => params[:page])
@agree_list = list.map(&:profile)

1

如果您不想使用配置文件或遇到配置文件问题,也可以确保返回ActiveRecord :: Relation而不是数组。例如,将同意列表列表更改为用户ID列表,然后对这些ID进行IN来返回关系。

def agree_list
  list = OpinionRating.find_all_by_opinion_id(params[:id])
  @agree_id_list = []
  list.each do |r|
    user = Profile.find(r.profile_id)
    @agree_id_list << user.id
  end
  @agree_list = User.where(:id => @agree_id_list) 
end

从数据库的角度来看,这是低效的,但是对于will_paginate配置文件有问题的任何人都是一种选择。


0

我利用了Rails协会,并想出了一种新方法:

def agree_list
  o = Opinion.find(params[:id])
  @agree_list = o.opinion_ratings(:conditions => {:agree => true}, :order => 'created_at DESC').paginate :page => params[:page]
rescue ActiveRecord::RecordNotFound
  redirect_to(profile_opinion_path(session[:user]))
end

在我看来,我像这样查找个人资料:

<% @agree_list.each do |rating| %>
  <% user = Profile.find(rating.profile_id) %>
<% end %>

如果有更好的方法,请发表。我试图在OpinionRating模型中使用named_scope帮助器,但没有运气。这是我尝试过但无法正常工作的示例:

named_scope :with_profile, lambda {|id| { :joins => [:profile], :conditions => ['profile_id = ?', id] } }

但这似乎与使用find方法相同。

感谢您的所有帮助。


0

我正在使用Rails 3 ruby​​ 1.9.2。另外,我只是启动应用程序,因此不包括CSS或样式。

安装will_paginate:

宝石安装will_paginate

添加到Gemfile并运行包。

控制者

class DashboardController < ApplicationController
    include StructHelper

    def show
        @myData =structHelperGet.paginate(:page => params[:page])
    end

end

StructHelper模块查询服务,而不是数据库。structHelperGet()返回记录数组。

不知道更复杂的解决方案是伪造模型,还是经常抓取数据并不时地重新创建sqllite表,并拥有要查询的真实模型。刚刚创建了我的第一个Rails应用程序。

视图

<div id="Data">
                <%= will_paginate @myData%>
                    <table>
                    <thead>
                    <tr>
                    <th>col 1</th>
                    <th>Col 2</th>
                    <th>Col 3</th>
                    <th>Col 4</th>
                    </tr>
                    </thead>
                    </tbody>
                    <% @myData.each do |app| %>
                        <tr>
                           <td><%=app[:col1]%> </td>
                           <td><%=app[:col2]%> </td>
                           <td><%=app[:col3]%> </td>
                           <td><%=app[:col4]%> </td>
                        </tr>

                    <% end %>
                    </tbody>
                    </table>
                <%= will_paginate @myData%>
                </div>

这将使您分页默认为每页30行。

如果您尚未阅读http://railstutorial.org,请立即开始阅读。


0

即使没有任何宝石,也可以实现分页。看到了如何分页数组?。kaminari gems文档中的简单实现。请参阅以下我从kaminari gems doc获得的示例

arr = (1..100).to_a
page, per_page = 1, 10
arr[((page - 1) * per_page)...(page * per_page)] #=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
page, per_page = 2, 10
arr[((page - 1) * per_page)...(page * per_page)] #=> [11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.