4 Stimmen

Suche nach dem nächsten ActiveRecord-Modellobjekt in der Datenbank anhand des angegebenen Objekts

Ich habe ein ActiveRecord-Modellobjekt @gallery die eine Zeile in der MYSQL-Tabelle Galleries darstellt. Gibt es eine Möglichkeit für mich zu fragen @gallery um mir die ID des nächsten Galerieobjekts in der Tabelle zu geben?

Die naheliegendste Möglichkeit, dies zu tun, besteht darin, :

@galleries = Gallery.find(:all)
index = @galleries.index(@gallery)

@nextgallery = @galleries[index+1]

aber dann muss ich dies nilsafe und ich bin unnötig machen einen weiteren DB-Aufruf, um alle Datensätze zu holen. Jeder andere Weg aus?

8voto

Daniel Dener Punkte 679

Ich habe in ähnlicher Situation gewesen und ich am Ende mit paar Lösungen mit Rails 3.1.3, mit entweder Klasse Methoden oder Umfang (named_scope in Rails 2.x). Dieser Ansatz wird auch mit nicht sequentiellen ids arbeiten.

Beispiel für Klassenmethoden unter Verwendung eines Post-Modells:

def next
  Post.where("posts.id > ?", self.id).order("posts.id ASC").limit(1)
end

def previous
  Post.where("posts.id < ?", self.id).order("posts.id DESC").limit(1)
end

Dies könnte wie folgt verwendet werden:

post = Post.find(5)

next_post = post.next
 => [#<Post id: 6, ...]

previous_post = post.previous
 => [#<Post id: 4, ...]

Und für Bereiche, mit Lambda sollte etwas wie sein:

  scope :next, lambda { |i| {:conditions => ["#{self.table_name}.id > ?", i.id], :order => "#{self.table_name}.id ASC", :limit => 1} }
  scope :previous, lambda { |i| {:conditions => ["#{self.table_name}.id < ?", i.id], :order => "#{self.table_name}.id DESC", :limit => 1} }

2voto

Chuck Vose Punkte 4453

Sind Sie wirklich sicher, dass Sie einen zweiten db-Anruf tätigen? Wenn ja, ist das wirklich wichtig? Ist dies tief in einer 4x verschachtelten Schleife, wo jeder Aufruf wichtig ist?

Wenn nicht, kann Ihnen die Voroptimierung zum Verhängnis werden. AR:B macht eine Menge Caching und iirc find(:all) gibt ein Array oder Hash zurück, so index+1 sollte in Ordnung sein.

2voto

klew Punkte 14589

Zunächst sollten Sie einige Kriterien festlegen, um die Reihenfolge Ihrer Galerien zu bestimmen. Wenn Sie in MySQL

 SELECT * FROM galeries

können Sie die Reihenfolge der zurückgegebenen Datensätze ändern. Wenn Sie sie beispielsweise nach dem Erstellungszeitpunkt ordnen, können Sie etwa so vorgehen:

 @nextgallery = Gallery.find(
                   :first, 
                   :order => "created_at ASC", 
                   :conditions => "created_at > #{@gallery.created_at}"
                 )

In diesem Beispiel sollten Sie vorsichtig sein mit @gallery.created_at weil Rails die Zeit in der Datenbank im GMT +0 Zeitformat speichert, aber in @gallery.created_at es ist mit Ihrer lokalen Konfiguration (zum Beispiel +2 h). Um sie zu ändern, verwenden Sie: @gallery.created_at.gmtime.to_s

0voto

Veger Punkte 35866

Der von Ihnen vorgestellte Code ist eine gute Sache. Die find(:all) Methode holt standardmäßig alle Datensätze aus der Tabelle "Galerien", und zwar auf folgende Weise (Sie können es sehen, wenn Sie WEBrick im Entwicklungsmodus ausführen)

SELECT * FROM galleries

Die Ergebnisse dieser Abfrage werden zwischengespeichert und bei jedem Zugriff auf @galaeries wiederverwendet. Dies ist auch sichtbar (wenn WEBrick läuft), da keine weiteren Datenbankaufrufe erfolgen.

0voto

DanSingerman Punkte 35071

Ich glaube nicht, dass es eine Möglichkeit gibt, die nächste Galerie aus Ihrer @gallery-Instanz zu holen, ohne die Datenbank zu belasten.

Sie könnten jedoch nur einmal auf die Datenbank zugreifen, wenn Sie etwas wie folgt tun würden

@galleries = Gallery.find(:all)
@gallery = @galleries.detect{|g| g.id == params[:gallery_id]}
index = @galleries.index(@gallery)
@nextgallery = @galleries[index+1]

Sie treffen also nur einmal auf die Datenbank. Dies ist nur dann schlecht, wenn Sie eine große Anzahl von Galerien haben, in diesem Fall würde es Sinn machen, eine next Methode zu Ihrer Galerie, die auf die Datenbank zugreift

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X