【问题标题】:Ruby on Rails will_paginate an arrayRuby on Rails will_paginate 一个数组
【发布时间】:2011-05-20 04:02:52
【问题描述】:

我想知道是否有人可以解释如何在对象数组上使用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

谢谢

【问题讨论】:

  • 从谷歌搜索“rails paginate array”来到这里,我想与其他访问者分享kaminari 是我选择的rails 分页替代方案。优雅地处理数组。

标签: ruby-on-rails pagination will-paginate


【解决方案1】:

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

在你的config/initializers(我用will_paginate_array_fix.rb)的一个文件中,添加这个

require 'will_paginate/array'

然后你可以在数组上使用

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

【讨论】:

  • 这有帮助,但它没有正确显示视图中的分页。
  • 谁能告诉我——我们将如何在视图中呈现它? --- @array = my_array.paginate(:page => x, :per_page => y)
  • @Robbie Guilfoyle my_array.paginate(:page => params[:page], :per_page => 1) 这为我修复了分页 :)
【解决方案2】:

您可以使用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

您的数据库架构遵循正确的命名约定很重要,否则这一切都会中断。确保您使用 Database Migrations 创建表格,而不是手动创建表格。

这些关联将在您的模型上创建助手,使搜索变得更加容易。您可以使用 named_scopescope 让 Rails 为您执行此操作,而不是迭代 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

在任何一种情况下,您都可以在 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])

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。通过与名为 Categories 的联接表的多对多关系,喜欢对 Profile 表的意见。有了这个设置,你知道它会如何改变你上面提到的代码吗?
  • @Brian 我已经更新了我的示例,但除非您向我展示您的模型类,否则我无法确定。
  • Adam,我如何获得意见评级模型?如果我理解这个正确 Profile.with_opinion 返回具有指定 ID 的所有配置文件的列表?我需要的是从 OpinionRating 模型中获取一个配置文件列表,该模型属于_to :opinion 和 Opinion has_many :opinion_ratings。 Profile 模型通过 Categories 连接表链接到 Opinion 模型。
  • 这就是我使用数组的原因,因为我不确定如何查询数据库。
  • 嗯,感谢您的帮助,但我想我找到了问题的答案。不确定这是否是最有效的方法,但它确实有效。我将进一步研究 named_scope 并尝试在未来实现它。
【解决方案3】:

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

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

【讨论】:

    【解决方案4】:

    如果您不想使用配置文件或遇到问题,您也可以确保返回 ActiveRecord::Relation 而不是数组。例如,将agreement_list 更改为用户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 配置文件有问题的人来说,这是一个选择。

    【讨论】:

      【解决方案5】:

      我利用了 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 方法相同。

      感谢大家的帮助。

      【讨论】:

        【解决方案6】:

        我正在使用 rails 3 ruby​​ 1.9.2。另外,我刚刚启动应用程序,所以没有包含 css 或样式。

        安装 will_paginate:

        gem install will_paginate

        添加到 Gemfile 并运行 bundle。

        控制器

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

        【讨论】:

          【解决方案7】:

          即使没有任何 gem,你也可以实现分页。我看到了这个How do I paginate an Array?。 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]
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2017-06-02
            • 2011-03-13
            • 1970-01-01
            • 1970-01-01
            • 2011-01-02
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多