RubyonRails 将对数组进行分页

我想知道是否有人可以解释一下如何在对象数组上使用 将 _ 分页

例如,在我的网站上,我有一个意见部分,用户可以评价的意见。下面是我写的一个方法,用来收集那些评价过这个观点的用户:

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

Thank you

55561 次浏览

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

这就是 ActiveRecord Associations的作用。您应该仔细阅读该指南,如果您正在开发 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

重要的是,您的数据库模式要遵循正确的命名约定,否则所有这些都将被打破。确保使用 数据库迁移创建表,而不是手工创建。

这些关联将为您的模型创建帮助器,使搜索更加容易。不需要迭代 OpinionRatings 列表并手动收集用户,您可以使用 named_scopescope让 Rails 为您做到这一点,具体取决于您使用的是 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

无论哪种情况,您都可以在 OpinionRatings模型上调用 for(id)并传递一个 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])

Rails4.x 的更新: 大致相同:

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


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

不过,对于较新的 Rails,我倾向于使用 Kaminari进行分页:

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

The gem will_paginate will paginate both ActiveRecord queries and arrays.

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

I took advantage of rails associations, and came up with a new method:

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

In my view I looked up the profile like so:

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

如果有更好的方法,请张贴。我尝试在 OpinionRating 模型中使用 name _ scope 助手,但没有成功。下面是一个我尝试过但没有成功的例子:

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

不过,这似乎与使用 find 方法相同。

Thanks for all the help.

我正在使用 Rails 3 ruby 1.9.2。另外,我刚刚开始应用程序,所以没有 CSS 或样式包括在内。

安装 will _ pagination:

gem install will_paginate

添加到 Gemfile 并运行 bundle。

控制员

class DashboardController < ApplicationController
include StructHelper


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


end

Module structHelper 查询服务,而不是数据库。 StructHelperGet ()返回一个记录数组。

Not sure if a more sophisticated solution would be to fake a model, or to grab the data every so often and recreate a sqllite table once in a while and have a real model to query. Just creating my first rails app ever.

观景

<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,现在就开始读吧。

Will _ pagate 3.0的设计目的是利用 Rails 3中的新 ActiveRecord::Relation,因此默认情况下它只在关系上定义 paginate。它仍然可以与数组一起工作,但是您必须告诉 Rail 需要该部分。

config/initializers的文件中(我使用的是 will_paginate_array_fix.rb) ,添加以下代码

require 'will_paginate/array'

然后可以在数组上使用

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

如果您不想使用配置文件,或者在使用配置文件时遇到了麻烦,您还可以确保返回的是 ActiveRecord: : Relations 而不是 array。例如,将同意列表更改为用户 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 _ pagination 配置文件有问题的人来说,这是一个选项。

You can implement pagination even without any gem.I saw this 如何分页数组?. Simple implementation in kaminari gems doc. Please see the below example which i got from 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]