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
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)
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])
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)
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.
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.
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]
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.