2009-08-14 9 views

risposta

41

Se ogni titolo è unico ed è necessario alfabetico, provate questo nel 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 possibile collegare a quelli nella visualizzazione.

<%= 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. È possibile modificare title in qualsiasi attributo univoco (created_at, id, ecc.) Se è necessario un diverso ordinamento.

+0

Grazie !!!! è perfetta! :) – pollinoco

+0

@ Sam, sì, è per questo che ho detto "se ogni titolo è unico". – ryanb

+0

scusa Ryan, devo diventare cieco, potresti: condizioni => ["titolo>? E id>?", Titolo, id] per aggirare. aggiungere un indice sul titolo è un po 'critico qui a meno che non sia un'app giocattolo. –

-1

È davvero necessario 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 

Naturalmente "this_post" è il post corrente.

Se i tuoi post sono memorizzati con una colonna auto_increment e non riutilizzi ID puoi semplicemente utilizzare 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.

+1

si sta andando ad avere bisogno di un ordine così ... –

+0

Sì, hai ragione, un ordine è necessario. Ho aggiornato la mia risposta. –

+0

thak you !, ma se necessario rilevare alfabetico successivo o precedente: titolo post? – pollinoco

0

Dai alla prova il will_paginate Gem. Fornisce tutte le funzionalità necessarie per impaginare le voci del tuo post. learn here too

Puoi anche guardare here per esempio il codice se vuoi aggiungere i pulsanti successivo e precedente.

+3

will_paginate è inadatto per questo problema. Quando stai mostrando un post, hai a che fare con un singolo post, non con una raccolta. –

1

Ecco come l'ho fatto. In primo luogo, aggiungere un paio di named scopes al 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 

Nota l'uso dell'opzione :select per limitare i campi, perché probabilmente non si vuole recuperare un completamente popolata Post esempio solo per mostrare i link .

Poi 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 riscritta per essere meno prolissa, 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.

L'importante è l'uso delle istruzioni if perché se si è sul primo post, non saranno post precedenti e viceversa, se si è nell'ultimo post, non saranno post successivi.

Infine, è sufficiente chiamare il metodo di supporto alla vostra vista:

<%= sidebar_navigation_links %> 
+0

Ciao John, grazie per la tua risposta ... ma ho un problema ... Se distruggo un post, perdo l'ID consecutivo e non saprei chi è il post successivo o il post precedente, perché Post.find_by_id (id - 1,: select => 'title, slug etc ...') altro problema è che non ho un permalink e navigo in questo momento con id ma se sostituisco ": href => previous_post.permalink "di": href => previous_post.id " the href = emty :) puoi aiutarmi? grazie ancora! – pollinoco

13

Ho usato i metodi del modello come di seguito 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, io faccio solo questo:

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

Il mio metodo vi permetterà di utilizzare a scopi automaticamente modello. Ad esempio, potresti voler visualizzare solo post che sono "pubblicati".

nel modello:

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

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

Secondo lei

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

Nel vostro controller

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

Associated RSpec:

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.

0

Ho creato la gemma proximal_records in particolare per questo tipo di attività e funziona su qualsiasi ambito creato dinamicamente nel 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 
Problemi correlati