Rails: link “post successivo” e “post precedente” nella mia vista spettacolo, come?

Sono nuovo in Rails … sorridi

Nella mia aplicazione del blog voglio avere un link “post precedente” e un link “post successivo” nella parte inferiore della mia vista spettacolo.

Come faccio a fare questo?

Grazie!

Se ogni titolo è unico e hai bisogno dell’alfabeto, prova questo nel tuo modello Post .

 def previous_post self.class.first(:conditions => ["title < ?", title], :order => "title desc") end def next_post self.class.first(:conditions => ["title > ?", title], :order => "title asc") end 

È quindi ansible colbind a quelli nella vista.

 <%= link_to("Previous Post", @post.previous_post) if @post.previous_post %> <%= link_to("Next Post", @post.next_post) if @post.next_post %> 

Non testato, ma dovrebbe farti chiudere. Puoi cambiare title in qualsiasi attributo univoco ( created_at , id , ecc.) Se hai bisogno di un diverso ordinamento.

Ho usato i metodi del modello come sotto per evitare il problema in cui id + 1 non esiste ma id + 2 lo fa.

 def previous Post.where(["id < ?", id]).last end def next Post.where(["id > ?", id]).first end 

Nel mio codice di vista, faccio solo questo:

  - if @post.previous = link_to "< Previous", @post.previous - if @post.next = link_to "Next >", @post.next 

Il mio metodo ti consentirà di utilizzare automaticamente gli ambiti del modello. Ad esempio, potresti voler visualizzare solo post che sono “pubblicati”.

Nel tuo modello:

 def self.next(post) where('id < ?', post.id).last end def self.previous(post) where('id > ?', post.id).first end 

Secondo te

 <%= link_to 'Previous', @posts.previous(@post) %> <%= link_to 'Next', @posts.next(@post) %> 

Nel tuo controller

 @photos = Photo.published.order('created_at') 

Test RSpec associati:

 describe '.next' do it 'returns the next post in collection' do fourth_post = create(:post) third_post = create(:post) second_post = create(:post) first_post = create(:post) expect(Post.next(second_post)).to eq third_post end it 'returns the next post in a scoped collection' do third_post = create(:post) decoy_post = create(:post, :published) second_post = create(:post) first_post = create(:post) expect(Post.unpublished.next(second_post)).to eq third_post end end describe '.previous' do it 'returns the previous post in collection' do fourth_post = create(:post) third_post = create(:post) second_post = create(:post) first_post = create(:post) expect(Post.previous(third_post)).to eq second_post end it 'returns the previous post in a scoped collection' do third_post = create(:post) second_post = create(:post) decoy_post = create(:post, :published) first_post = create(:post) expect(Post.unpublished.previous(second_post)).to eq first_post end end 

Nota: ci saranno piccoli problemi quando si raggiunge il primo / ultimo post di una raccolta. Raccomando un helper di visualizzazione per mostrare in modo condizionale il pulsante precedente o successivo solo se esiste.

Questo è come l’ho fatto. In primo luogo, aggiungi un paio di ambiti nominati al tuo modello Post :

 def previous Post.find_by_id(id - 1, :select => 'title, slug etc...') end def next Post.find_by_id(id + 1, :select => 'title, slug etc...') end 

Notare l’uso dell’opzione :select per limitare i campi perché probabilmente non si desidera recuperare un’istanza Post completamente popolata solo per mostrare i collegamenti.

Quindi nel mio posts_helper ho questo metodo:

 def sidebar_navigation_links next_post = @post.next previous_post = @post.previous links = '' if previous_post links << content_tag(:h3, 'Previous') links << content_tag(:ul, content_tag(:li, content_tag(:a, previous_post.title, :href => previous_post.permalink))) end if next_post links << content_tag(:h3, 'Next', :class => 'next') if previous_post links << content_tag(:h3, 'Next') if previous_post.nil? links << content_tag(:ul, content_tag(:li, content_tag(:a, next_post.title, :href => next_post.permalink))) end content_tag(:div, links) end 

Sono sicuro che questo potrebbe essere refactored per essere meno prolisso, ma l’intento è chiaro. Ovviamente i tuoi requisiti di markup saranno diversi dai miei, quindi potresti non scegliere di usare un elenco non ordinato, ad esempio.

La cosa importante è l’uso delle istruzioni if , perché se sei sul primo post non saranno post precedenti e viceversa, se sei sull’ultimo post, non saranno post successivi.

Infine, chiama semplicemente il metodo helper dalla tua vista:

 <%= sidebar_navigation_links %> 

Dare una prova alla gem will_paginate . Fornisce tutte le funzionalità necessarie per impaginare le voci del tuo post. impara anche qui

Puoi anche guardare qui per esempio codice se vuoi aggiungere i pulsanti Avanti e Indietro.

Ho creato gem proximal_records soprattutto per questo tipo di attività e funziona su qualsiasi ambito creato dynamicmente nel tuo modello.

https://github.com/dmitry/proximal_records

Esempio di base:

 class Article < ActiveRecord::Base include ProximalRecords end scope = Article.title_like('proximal').order('created_at DESC, title ASC') current_record = scope.to_a[5] p, n = current_record.proximal_records(scope) # will find record 5 and 7 

Hai davvero bisogno di eseguire 2 query, una per ciascuna di “prev” e “next”. Supponiamo che tu abbia una colonna created_at.

Pseudo-codice:

 # get prev select * from posts where created_at < #{this_post.created_at} order by created_at desc limit 1 # get next select * from posts where created_at > #{this_post.created_at} order by created_at desc limit 1 

Ovviamente “this_post” è il post corrente.

Se i tuoi post sono archiviati con una colonna auto_increment e non riutilizzi ID puoi semplicemente usare la colonna id al posto di created_at – la colonna id dovrebbe essere già indicizzata. Se si desidera utilizzare la colonna created_at, si vorrà sicuramente avere un indice su quella colonna.