Ruby on Rails will_paginate an array

匿名 (未验证) 提交于 2019-12-03 01:54:01

问题:

I was wondering if someone could explain how to use will_paginate on an array of objects?

For example, on my site I have an opinion section where users can rate the opinions. Here's a method I wrote to gather the users who have rated the opinion:

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

回答1:

will_paginate 3.0 is designed to take advantage of the new ActiveRecord::Relation in Rails 3, so it defines paginate only on relations by default. It can still work with an array, but you have to tell rails to require that part.

In a file in your config/initializers (I used will_paginate_array_fix.rb), add this

require 'will_paginate/array'

Then you can use on arrays

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


回答2:

You could use Array#from to simulate pagination, but the real problem here is that you shouldn't be using Array at all.

This is what ActiveRecord Associations are made for. You should read that guide carefully, there is a lot of useful stuff you will need to know if you're developing Rails applications.

Let me show you a better way of doing the same thing:

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

It's important that your database schema is following the proper naming conventions or all this will break. Make sure you're creating your tables with Database Migrations instead of doing it by hand.

These associations will create helpers on your models to make searching much easier. Instead of iterating a list of OpinionRatings and collecting the users manually, you can make Rails do this for you with the use of named_scope or scope depending on whether you're using Rails 2.3 or 3.0. Since you didn't specify, I'll give both examples. Add this to your OpinionRating class:

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

In either case you can call for(id) on the OpinionRatings model and pass it an 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)

The upshot of all this is that you can now easily paginate:

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

Update for Rails 4.x: more or less the same:

scope :agreed, ->{ where agreed: true }  def self.for(id)   joins(:opinion).where(opinion: { id: id }) end 

Although for newer Rails my preference is kaminari for pagination:

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!