web-dev-qa-db-fra.com

Ruby on Rails will_paginate an array

Je me demandais si quelqu'un pouvait expliquer comment utiliser will_paginate sur un tableau d'objets?

Par exemple, sur mon site, j'ai une section d'opinion où les utilisateurs peuvent évaluer les opinions. Voici une méthode que j'ai écrite pour rassembler les utilisateurs qui ont évalué l'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

Merci

70
Brian

will_paginate 3.0 est conçu pour tirer parti du nouveau ActiveRecord::Relation in Rails 3, donc il définit paginate uniquement sur les relations par défaut. Il peut toujours fonctionner avec un tableau, mais vous devez dire Rails pour exiger cette partie.

Dans un fichier dans votre config/initializers (J'ai utilisé will_paginate_array_fix.rb), Ajoute ça

require 'will_paginate/array'

Ensuite, vous pouvez utiliser sur des tableaux

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

Vous pouvez utiliser Array#from Pour simuler la pagination, mais le vrai problème ici est que vous ne devriez pas du tout utiliser Array.

C'est pourquoi associations ActiveRecord sont faits pour. Vous devriez lire ce guide attentivement, il y a beaucoup de choses utiles que vous devrez savoir si vous développez des applications Rails.

Permettez-moi de vous montrer une meilleure façon de faire la même chose:

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

Il est important que votre schéma de base de données respecte les conventions de dénomination appropriées, sinon tout cela se briserait. Assurez-vous de créer vos tables avec Migrations de bases de données au lieu de le faire à la main.

Ces associations créeront des aides sur vos modèles pour faciliter la recherche. Au lieu d'itérer une liste d'OperationRatings et de collecter les utilisateurs manuellement, vous pouvez faire Rails le faire pour vous en utilisant named_scope Ou scope selon que vous utilisez Rails 2.3 ou 3.0. Comme vous ne l'avez pas spécifié, je vais donner les deux exemples. Ajoutez ceci à votre classe 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

Dans les deux cas, vous pouvez appeler for(id) sur le modèle OpinionRatings et lui transmettre un identifiant:

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)

Le résultat de tout cela est que vous pouvez maintenant facilement paginer:

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

Mise à jour pour Rails 4.x: plus ou moins le même:

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

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

Bien que pour les nouveaux Rails ma préférence est kaminari pour la pagination:

@ratings = @ratings.page(params[:page])
9
Adam Lassek

Le bijou will_paginate paginera les requêtes et les tableaux ActiveRecord.

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

Si vous ne souhaitez pas utiliser le fichier de configuration ou rencontrez des problèmes avec lui, vous pouvez également vous assurer de renvoyer un ActiveRecord :: Relation au lieu d'un tableau. Par exemple, modifiez à la place la liste d'accord pour être une liste d'ID utilisateur, puis effectuez un IN sur ces ID pour renvoyer une relation.

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

C'est inefficace du point de vue de la base de données, mais c'est une option pour quiconque a des problèmes avec le fichier de configuration will_paginate.

1
mcclaskc

J'utilise Rails 3 Ruby 1.9.2. De plus, je ne fais que commencer l'application, donc aucun CSS ni style n'est inclus).

Installez will_paginate:

installation de gem will_paginate

Ajoutez à Gemfile et exécutez le bundle.

Contrôleur

class DashboardController < ApplicationController
    include StructHelper

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

end

le module StructHelper interroge un service, pas une base de données. structHelperGet () renvoie un tableau d'enregistrements.

Je ne sais pas si une solution plus sophistiquée serait de simuler un modèle ou de récupérer les données de temps en temps et de recréer une table sqllite de temps en temps et d'avoir un vrai modèle à interroger. Je viens de créer ma première Rails app jamais.

Voir

<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>

Cela vous donnera une pagnation des 30 lignes par défaut par page.

Si vous n'avez pas encore lu http://railstutorial.org , commencez à le lire maintenant.

0
mpechner

Vous pouvez implémenter la pagination même sans gemme. J'ai vu cela Comment puis-je paginer un tableau? . Implémentation simple dans les gemmes kaminari doc. S'il vous plaît voir l'exemple ci-dessous que j'ai obtenu de 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]
0
Jose Kj

J'ai profité des associations Rails, et j'ai trouvé une nouvelle méthode:

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

À mon avis, j'ai recherché le profil comme suit:

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

Veuillez publier s'il existe une meilleure façon de procéder. J'ai essayé d'utiliser l'assistant named_scope dans le modèle OpinionRating sans succès. Voici un exemple de ce que j'ai essayé, mais qui ne fonctionne pas:

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

Cela semblait être la même chose que d'utiliser la méthode find.

Merci pour votre aide.

0
Brian