web-dev-qa-db-de.com

Schienen: Nächsten/vorherigen Datensatz

Meine App enthält Fotos, die zu Nutzern gehören.

In einer Foto-Show # möchte ich "Mehr von diesem Benutzer" anzeigen und ein nächstes und vorheriges Foto dieses Benutzers anzeigen. Es wäre gut, wenn das nächste/vorherige Foto in id-Reihenfolge oder das nächste/vorherige Foto in created_at-Reihenfolge ist.

Wie würden Sie diese Art von Abfrage für ein nächstes/vorheriges Foto oder für mehrere nächste/vorherige Fotos schreiben?

45
Andrew

Versuche dies:

class User
  has_many :photos
end


class Photo
  belongs_to :user

  def next
    user.photos.where("id > ?", id).first
  end

  def prev
    user.photos.where("id < ?", id).last
  end

end

Jetzt kannst du:

photo.next
photo.prev
86
Harish Shetty

Es führte mich auch zu einer Lösung für mein Problem. Ich habe versucht, einen Next/Prev für einen Artikel zu erstellen, keine assoziierten Assoziationen. endete so etwas in meinem Modell:

  def next
    Item.where("id > ?", id).order("id ASC").first || Item.first
  end

  def previous
    Item.where("id < ?", id).order("id DESC").first || Item.last
  end

Auf diese Weise schleift er sich um, vom letzten Element geht es zum ersten und umgekehrt ... Ich rufe in meinen Ansichten einfach @item.next auf.

16
Cremz

Nicht sicher, ob dies eine Änderung in Rails 3.2+ ist, aber anstelle von:

model.where("id < ?", id).first

für den vorigen. Du musst

.where("id > ?", id).last

Es scheint, dass die "Reihenfolge nach" falsch ist, also geben Sie zuerst den ersten Datensatz in der Datenbank an, denn wenn Sie 3 Elemente unter dem aktuellen Wert [1,3,4] haben, ist der "erste" 1, aber das letzte ist das, nach dem Sie gesucht haben. Sie können auch eine Sortierung nach dem wo anwenden, aber das ist ein zusätzlicher Schritt.

8
jwilcox09
class Photo < ActiveRecord::Base
  belongs_to :user
  scope :next, lambda {|id| where("id > ?",id).order("id ASC") } # this is the default ordering for AR
  scope :previous, lambda {|id| where("id < ?",id).order("id DESC") }

  def next
    user.photos.next(self.id).first
  end

  def previous
    user.photos.previous(self.id).first
  end
end

Dann kannst du:

photo.previous
photo.next
3
Zernel

Sie können einige Optionen an die where-Methode übergeben:

Für das nächste Foto:

Photo.where(:user_id => current_user.id, :created_at > current_photo.created_at).order("created_at").first

Vorheriges Foto

Photo.where(:user_id => current_user.id, :created_at < current_photo.created_at).order("created_at").last

Ich kann das erste/letzte gemischt haben.

2
Jordan Schwartz

Möglicherweise möchten Sie Nexter überprüfen. Es funktioniert für jeden dynamisch erstellten Bereich, anstatt sich auf einen in Ihrem Modell fest codierten Bereich zu verlassen.

1
charlysisto
class Photo < ActiveRecord::Base
  belongs_to :user

  default_scope { order('published_at DESC, id DESC') }

  def next
    current = nil
    user.photos.where('published_at >= ?', published_at).each do |p|
      if p.id == id then break else current = p end
    end
    return current
  end

  def previous
    current = nil
    user.photos.where('published_at <= ?', published_at).reverse.each do |p|
      if p.id == id then break else current = p end
    end
    return current
  end
end

Ich habe festgestellt, dass die Antworten, die ich bereits hier habe, meinem Fall nicht dienten. Stellen Sie sich vor, Sie möchten ein vorheriges oder nächstes basierend auf dem Datum, an dem das Datum veröffentlicht wurde, aber einige Fotos werden am selben Datum veröffentlicht. Diese Version durchläuft die Fotos in der Reihenfolge, in der sie auf der Seite gerendert werden, und nimmt die vor und nach dem aktuellen in der Sammlung auf.

1
NealJMD

Ändern Sie Ihre app/models/application_record.rb in den folgenden Code:

class ApplicationRecord < ActiveRecord::Base
  self.abstract_class = true

  def next
    self.class.where("id > ?", id).order("id ASC").first || self.class.first
  end

  def previous
   self.class.where("id < ?", id).order("id DESC").first || self.class.last
  end
end

Dann können Sie next () und previous () in allen Ihren Modellen verwenden.

0
Oldwolf Pang

Dies sollte funktionieren, und ich denke, es ist effizienter als die anderen Lösungen, da es jeden Datensatznicht oberhalb oder unterhalb des aktuellen Datensatzes abruft, um zum nächsten oder vorherigen zu gelangen:

def next
  # remember default order is ascending, so I left it out here
  Photo.offset(self.id).limit(1).first
end

def prev
  # I set limit to 2 because if you specify descending order with an 
  # offset/limit query, the result includes the offset record as the first
  Photo.offset(self.id)limit(2).order(id: :desc).last
end

Dies ist meine erste Antwort, die auf StackOverflow geschrieben wurde, und diese Frage ist ziemlich alt ... Ich hoffe, jemand sieht es :)

0
jinstrider2000