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?
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
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.
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.
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
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é.
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.
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.
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.
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 :)