web-dev-qa-db-fra.com

Rails: Obtenir l'enregistrement suivant/précédent

Mon application contient des photos appartenant à des utilisateurs.

Dans une vue # photo, j'aimerais afficher "Plus de cet utilisateur" et afficher une photo précédente et suivante de cet utilisateur. Je serais bien avec ceux-ci étant la photo suivante/précédente dans l'ordre id ou la photo suivante/précédente dans l'ordre created_at.

Comment écririez-vous ce type de requête pour une photo suivante/précédente ou pour plusieurs photos suivantes/précédentes?

45
Andrew

Essaye ça:

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

Maintenant vous pouvez:

photo.next
photo.prev
86
Harish Shetty

Cela m’a également amené à trouver une solution à mon problème. J'essayais de faire un prochain/prev pour un article, aucune association impliquée. fini par faire quelque chose comme ça dans mon modèle:

  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

De cette façon, la boucle tourne, du dernier élément à la première et dans l’inverse… .. J'appelle simplement @item.next à mon avis par la suite.

16
Cremz

Vous ne savez pas s'il s'agit d'un changement dans Rails 3.2+, mais au lieu de:

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

pour le précédent. Tu dois faire

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

Il semble que la "commande par" soit fausse. Par conséquent, commencez par vous donner le premier enregistrement de la base de données, car si vous avez 3 éléments inférieurs au courant, [1,3,4], le "premier" est 1, mais ce dernier est celui que vous recherchez. Vous pouvez également appliquer une sorte à après l’endroit, mais c’est une étape supplémentaire.

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

Ensuite vous pouvez:

photo.previous
photo.next
3
Zernel

Vous pouvez passer quelques options dans la méthode where:

Pour la photo suivante:

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

Photo précédente

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

Je peux avoir le premier/dernier mélangé.

2
Jordan Schwartz

Vous voudrez peut-être vérifier Nexter . Il fonctionne sur n’importe quelle étendue créée de manière dynamique au lieu de s’en remettre à celle codée en dur dans votre modèle.

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

J'ai trouvé que les réponses déjà ici ne servaient pas mon cas. Imaginez que vous souhaitiez une précédente ou une suivante en fonction de la date de publication, mais que certaines photos sont publiées à la même date. Cette version parcourt les photos dans l’ordre dans lequel elles sont affichées sur la page et prend celles avant et après la photo actuelle de la collection.

1
NealJMD

Modifiez votre app/models/application_record.rb avec le code suivant:

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

Ensuite, vous pouvez utiliser next () et previous () dans tous vos modèles.

0
Oldwolf Pang

Cela devrait fonctionner, et je pense que c'est plus efficace que les autres solutions dans la mesure où il ne récupère pas chaque enregistrement au-dessus ou au-dessous de l'actuel, juste pour aller au suivant ou précédent:

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

Ceci est ma première réponse sur StackOverflow, et cette question est assez ancienne ... J'espère que quelqu'un la verra :)

0
jinstrider2000