Ruby on Rails wird ein Array_paginieren

72

Ich habe mich gefragt, ob jemand erklären kann, wie man will_paginate für ein Array von Objekten verwendet.

Auf meiner Website habe ich beispielsweise einen Meinungsbereich, in dem Benutzer die Meinungen bewerten können. Hier ist eine Methode, die ich geschrieben habe, um die Benutzer zu sammeln, die die Meinung bewertet haben:

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

Vielen Dank

Brian
quelle
1
Nachdem ich von einer Google-Suche nach "Rails Paginate Array" hierher gekommen war, wollte ich anderen Besuchern mitteilen, dass Kaminari die Alternative für Rails Paginierung ist, für die ich mich entschieden habe. Behandelt Arrays elegant.
Tod Birdsall

Antworten:

218

will_paginate 3.0 wurde entwickelt, um die Vorteile von ActiveRecord::RelationRails 3 zu nutzen. Daherpaginate werden standardmäßig nur Relationen definiert . Es kann immer noch mit einem Array funktionieren, aber Sie müssen den Schienen mitteilen, dass sie dieses Teil benötigen.

Fügen Sie dies in einer Datei in Ihrer config/initializers(von mir verwendeten will_paginate_array_fix.rb) hinzu

require 'will_paginate/array'

Dann können Sie auf Arrays verwenden

my_array.paginate(:page => x, :per_page => y)
Keithepley
quelle
Dies hat geholfen, aber es zeigt die Paginierung in der Ansicht nicht richtig.
Robbie Guilfoyle
4
Kann mir jemand sagen - wie werden wir es in Sichtweite rendern? --- @array = my_array.paginate (: page => x ,: per_page => y) <% = will_paginate @ array%>
kamal
1
@Robbie Guilfoyle my_array.paginate (: page => params [: page] ,: per_page => 1) Dies hat die Paginierung für mich
behoben
9

Sie könnten verwenden Array#from, um die Paginierung zu simulieren, aber das eigentliche Problem hier ist, dass Sie überhaupt nicht verwenden sollten Array.

Dafür sind ActiveRecord- Zuordnungen gemacht. Sie sollten diese Anleitung sorgfältig lesen. Es gibt viele nützliche Dinge, die Sie wissen müssen, wenn Sie Rails-Anwendungen entwickeln.

Lassen Sie mich Ihnen einen besseren Weg zeigen, dasselbe zu tun:

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

Es ist wichtig, dass Ihr Datenbankschema den richtigen Namenskonventionen folgt, da sonst alles kaputt geht. Stellen Sie sicher, dass Sie Ihre Tabellen mit Datenbankmigrationen erstellen anstatt sie manuell auszuführen.

Diese Zuordnungen erstellen Helfer für Ihre Modelle, um die Suche erheblich zu vereinfachen. Anstatt eine Liste von OpinionRatings zu iterieren und die Benutzer manuell zu sammeln, können Sie Rails dazu bringen, dies für Sie zu tun, indem Sie Rails 2.3 oder 3.0 verwenden named_scopeoder davon scopeabhängen, ob Sie Rails 2.3 oder 3.0 verwenden. Da Sie nicht angegeben haben, werde ich beide Beispiele geben. Fügen Sie dies Ihrer OpinionRating-Klasse hinzu:

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 jedem Fall können Sie anrufen for(id)auf demOpinionRatings Modell und ihm eine ID übergeben:

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)

Das Ergebnis all dessen ist, dass Sie jetzt leicht paginieren können:

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

Update für Rails 4.x: mehr oder weniger gleich:

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

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

Obwohl ich für neuere Rails Kaminari für die Paginierung bevorzuge :

@ratings = @ratings.page(params[:page])
Adam Lassek
quelle
Nun, die Assoziationen sind Tabelle Opinion has_many: opinion_ratings und gehört_to: opinion. Eine Meinung wird der Profiltabelle durch eine Viele-zu-Viele-Beziehung mit einer Verknüpfungstabelle namens Kategorien gefallen. Wissen Sie mit dieser Einstellung, wie sich der oben erwähnte Code ändern würde?
Brian
@Brian Ich habe mein Beispiel aktualisiert, kann aber nicht sicher sein, es sei denn, Sie zeigen mir Ihre Modellklassen.
Adam Lassek
Adam, wie komme ich zum Meinungsbewertungsmodell? Wenn ich dieses Recht verstehe, gibt Profile.with_opinion eine Liste aller Profile mit der angegebenen ID zurück? Was ich brauche, ist eine Liste von Profilen aus dem OpinionRating-Modell, das zu: opinion und Opinion has_many: opinion_ratings gehört. Das Profilmodell ist über die Verknüpfungstabelle "Kategorien" mit dem Meinungsmodell verknüpft.
Brian
Aus diesem Grund habe ich ein Array verwendet, da ich nicht sicher war, wie ich die Datenbank abfragen soll.
Brian
Nun, ich schätze die Hilfe, aber ich glaube, ich habe die Antwort auf meine Frage gefunden. Ich bin mir nicht sicher, ob es der effizienteste Weg ist, aber es funktioniert. Ich werde mich noch einmal mit named_scope befassen und versuchen, dies in Zukunft zu implementieren.
Brian
4

Der Edelstein will_paginatepaginiert sowohl ActiveRecord-Abfragen als auch Arrays.

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

Wenn Sie die Konfigurationsdatei nicht verwenden möchten oder Probleme damit haben, können Sie auch nur sicherstellen, dass Sie eine ActiveRecord :: Relation anstelle eines Arrays zurückgeben. Ändern Sie beispielsweise die Vereinbarung_Liste in eine Liste von Benutzer-IDs und führen Sie dann ein IN für diese IDs durch, um eine Beziehung zurückzugeben.

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

Dies ist aus Datenbanksicht ineffizient, aber eine Option für alle, die Probleme mit der Konfigurationsdatei will_paginate haben.

mcclaskc
quelle
0

Ich nutzte die Schienenverbände und fand eine neue Methode:

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

Aus meiner Sicht habe ich das Profil folgendermaßen nachgeschlagen:

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

Bitte posten Sie, wenn es einen besseren Weg gibt, dies zu tun. Ich habe ohne Glück versucht, den Helfer named_scope im OpinionRating-Modell zu verwenden. Hier ist ein Beispiel für das, was ich versucht habe, aber nicht funktioniert:

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

Das schien jedoch dasselbe zu sein wie die Find-Methode.

Danke für all die Hilfe.

Brian
quelle
0

Ich benutze Schienen 3 Rubin 1.9.2. Außerdem starte ich gerade die App, sodass keine CSS oder Stile enthalten sind.

Installieren Sie will_paginate:

gem install will_paginate

Zu Gemfile hinzufügen und Bundle ausführen.

Regler

class DashboardController < ApplicationController
    include StructHelper

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

end

Das Modul StructHelper fragt einen Dienst ab, keine Datenbank. structHelperGet () gibt ein Array von Datensätzen zurück.

Ich bin mir nicht sicher, ob eine komplexere Lösung darin besteht, ein Modell zu fälschen oder die Daten von Zeit zu Zeit abzurufen und ab und zu eine SQLite-Tabelle neu zu erstellen und ein echtes Modell zum Abfragen zu haben. Ich erstelle gerade meine erste Rails-App.

Aussicht

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

Dadurch erhalten Sie eine Pagnation der Standardzeilen von 30 Zeilen pro Seite.

Wenn Sie http://railstutorial.org noch nicht gelesen haben, lesen Sie es jetzt.

mpechner
quelle
0

Sie können die Paginierung auch ohne Edelstein implementieren. Ich habe dies gesehen. Wie paginiere ich ein Array? . Einfache Implementierung in Kaminari Gems Doc. Bitte sehen Sie das folgende Beispiel, das ich von Kaminari Gems Doc erhalten habe

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]
Jose Kj
quelle