it-swarm.it

Rails: ottieni il record successivo/precedente

La mia app ha foto che appartengono agli utenti.

In una foto in # show view mi piacerebbe mostrare "Altro da questo utente" e mostrare una foto successiva e precedente da quell'utente. Sarei a posto con queste foto precedenti/precedenti nell'ordine id o nella foto successiva/precedente nell'ordine created_at.

Come scriveresti questo tipo di query per una foto successiva/precedente o per più foto successive/precedenti?

45
Andrew

Prova questo:

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

Ora puoi:

photo.next
photo.prev
86
Harish Shetty

Mi porta anche a una soluzione per il mio problema. Stavo cercando di fare un next/prev per un oggetto, nessuna associazione coinvolta. ho finito per fare qualcosa del genere nel mio modello:

  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

In questo modo si aggira intorno, dall'ultimo elemento si passa al primo e viceversa. Ho appena chiamato @item.next nelle mie visualizzazioni in seguito.

16
Cremz

Non sono sicuro se questo è un cambiamento in Rails 3.2+, ma invece di:

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

per il precedente. Devi fare

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

Sembra che "order by" sia sbagliato, quindi prima datti il ​​primo record nel DB, perché se hai 3 voci inferiori alla corrente, [1,3,4], il "primo" è 1, ma quell'ultima è quella che stai cercando. Si potrebbe anche applicare un ordinamento a dopo il dove, ma questo è un passaggio in più.

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

Allora puoi:

photo.previous
photo.next
3
Zernel

Puoi passare alcune opzioni nel metodo where:

Per la prossima foto:

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

Foto precedente

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

Potrei avere il primo/ultimo mescolato.

2
Jordan Schwartz

Potresti voler controllare Nexter . Funziona su qualsiasi ambito creato dinamicamente invece di fare affidamento su un codice a codice fisso nel modello.

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

Ho trovato che le risposte già qui non sono state al mio caso. Immagina di volere un precedente o successivo in base alla data pubblicata, ma alcune foto sono pubblicate nella stessa data. Questa versione scorre le foto nell'ordine in cui sono visualizzate sulla pagina e prende quelle precedenti e successive a quella corrente nella raccolta.

1
NealJMD

Modifica la tua app/modelli/application_record.rb al seguente codice:

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

Quindi puoi usare next () e previous () in tutti i tuoi modelli.

0
Oldwolf Pang

Questo dovrebbe funzionare, e penso che sia più efficiente delle altre soluzioni in quanto non recupera ogni record sopra o sotto quello corrente solo per arrivare al successivo o precedente:

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

Questa è la mia prima risposta mai pubblicata su StackOverflow, e questa domanda è piuttosto vecchia ... Spero che qualcuno la veda :)

0
jinstrider2000