2009-08-14 12 views

Respuesta

41

Si cada título es único y necesita alfabético, intente esto en su modelo de 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 

A continuación, puede vincular a los de la vista.

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

No probado, pero debe llegarle cerca. Puede cambiar title a cualquier atributo único (created_at, id, etc.) si necesita un orden de clasificación diferente.

+0

Gracias !!!! ¡es perfecto! :) – pollinoco

+0

@Sam, sí, por eso dije "si cada título es único". – ryanb

+0

lo siento, Ryan, debo ir a ciegas, tu podrías: conditions => ["title>? And id>?", Title, id] para eludir. agregar un índice en el título es algo crítico aquí a menos que sea una aplicación de juguete. –

-1

Realmente solo necesita ejecutar 2 consultas, una para cada "prev" y "next". Supongamos que tiene una columna created_at.

Psuedo-código:

# 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 

Por supuesto "this_post" es el mensaje actual.

Si sus publicaciones se almacenan con una columna auto_increment y no vuelve a utilizar las ID, puede usar la columna de id en lugar de created_at - la columna id ya debe estar indexada. Si desea utilizar la columna created_at, definitivamente querrá tener un índice en esa columna.

+1

que se va a necesitar una orden de las inmediaciones ... –

+0

Sí, tienes razón, una orden por la que se necesita. Actualicé mi respuesta. –

+0

¡Gracias !, pero si es necesario, detectar alfabéticamente siguiente o anterior: ¿título de publicación? – pollinoco

0

Give the will_paginate Gem a try. Proporciona todas las funciones que necesita para paginar sus entradas de publicación. aprende here también

Puedes mirar here también, por ejemplo, código si quieres agregar los botones siguiente y anterior.

+3

will_paginate no es adecuado para este problema. Cuando muestra una publicación, se trata de una publicación individual, no de una colección. –

1

Así es como lo hice. En primer lugar, añadir un par de named scopes a su modelo 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 el uso de la opción :select para limitar los campos porque es probable que no desea recuperar un totalmente lleno con Post ejemplo, sólo para mostrar los enlaces .

Luego, en mi posts_helper que tienen este método:

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 

Estoy seguro de que esto podría ser readaptado a ser menos detallado, pero la intención es clara. Obviamente, sus requisitos de marcado serán diferentes a los míos, por lo que no puede optar por utilizar una lista desordenada, por ejemplo.

Lo importante es el uso de las declaraciones if porque si estás en la primera publicación, entonces no habrá ninguna publicación anterior y, a la inversa, si estás en la última publicación no serán entradas siguientes.

Por último, simplemente llame al método de ayuda desde su punto de vista:

<%= sidebar_navigation_links %> 
+0

Hola John, gracias por tu respuesta ... pero tengo un problema ... Si destruyo una publicación, pierdo la ID consecutiva y no sabría quién es la siguiente publicación o la anterior, porque Post.find_by_id (id - 1,: select => 'title, slug etc ...') otro problema es que no tengo un enlace permanente y navego en este momento por id pero si lo reemplazo ": href => previous_post.permalink "por": href => previous_post.id " href = emty :) me puedes ayudar? gracias de nuevo! – pollinoco

13

Usé los métodos de modelo de la siguiente manera para evitar el problema de que id + 1 no existe, pero id + 2 sí.

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

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

En mi código de la vista, acabo de hacer esto:

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

Mi método le permitirá utilizar de forma automática alcances modelo. Por ejemplo, es posible que solo desee mostrar las publicaciones que están "publicadas".

En su modelo:

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

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

En su opinión

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

En su controlador

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

Asociadas 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: habrá pequeños problemas cuando llegue a la primera/última publicación en una colección. Recomiendo un asistente de visualización para mostrar condicionalmente el botón anterior o siguiente solo si existe.

0

He creado la gema proximal_records especialmente para este tipo de tarea y funciona en cualquier ámbito creado dinámicamente en su modelo.

https://github.com/dmitry/proximal_records

Ejemplo básico:

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 
Cuestiones relacionadas