views:

453

answers:

5

Hi community...

I'm new in Rails... smile

In my blog aplication I want to have a "Previous post" link and a "Next post" link in the bottom of my show view.

How do I do this?

Thanks!

A: 

You really just need to run 2 queries, one for each of "prev" and "next". Lets assume you have a created_at column.

Psuedo-code:

# 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

Of course "this_post" is the current post.

If your posts are stored with an auto_increment column and you dont re-use IDs you can just use the id column in place of created_at - the id column should already be indexed. If you want to use the created_at column then you will definitely want to have an index on that column.

Cody Caughlan
you are going to need an order by as well ...
Sam Saffron
Yep, you're right, an order by is needed. I updated my response.
Cody Caughlan
thak you!, but if need detect next or previous alphabetical :title post?
pollinoco
+1  A: 

Give the will_paginate Gem a try. It provides all the features you need to paginate your post entries. learn here too

You can look at here too for example code if you want add next and previous buttons.

Kuya
will_paginate is a poor fit for this problem. When you're showing a post you're dealing with an individual post, not a collection.
John Topley
+1  A: 

This is how I did it. Firstly, add a couple of named scopes to your Post model:

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

Note the use of the :select option to limit the fields because you probably don't want to retrieve a fully-populated Post instance just for showing the links.

Then in my posts_helper I have this method:

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

I'm sure this could be refactored to be less verbose, but the intent is clear. Obviously your markup requirements will be different to mine, so you may not choose to use an unordered list, for example.

The important thing is the use of the if statements because if you're on the first post then they'll be no previous post and conversely, if you're on the last post they'll be no next post.

Finally, simply call the helper method from your view:

<%= sidebar_navigation_links %>
John Topley
Hi John, thank you for your answer... but i have a problem.... If I destroy a post, I lose the consecutive ID and I would not know who is the next post or previous post, because Post.find_by_id(id - 1, :select => 'title, slug etc...')other problem is that I don't have a permalink and i navigate in this moment by id but if I replace ":href => previous_post.permalink" by ":href => previous_post.id"the href = emty:)can you help me?thanks again!
pollinoco
+3  A: 

If each title is unique and you need alphabetical, try this in your Post model.

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

You can then link to those in the view.

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

Untested, but it should get you close. You can change title to any unique attribute (created_at, id, etc.) if you need a different sort order.

ryanb
Thank you!!!! is perfect!:)
pollinoco
@Sam, yep, which is why I said "if each title is unique".
ryanb
sorry Ryan, I must be going blind, your could :conditions => ["title > ? and id > ?", title, id] to work around. adding an index on title is kind of critical here unless its a toy app.
Sam Saffron
A: 

Hi community Thanks for your responses! I have

in posts_helper.rb

def sidebar_navigation_links
  next_post = @post.next
  previous_post = @post.previous
  links = ''
  if previous_post
    links << content_tag(:a, 'Previous', :href => previous_post.id)
  end
  if next_post
    links << content_tag(:a, 'Next', :href => next_post.id)
  end
  content_tag(:div, links)
end

in model post (mistakes? sure)

  def previous
    Post.find_by_id(:select => 'id', :conditions => ["created_at < :created_at", { :created_at => '#{post.created_at}' }])
  end

  def next
   Post.find_by_id(:select => 'id', :conditions => ["created_at > :created_at", { :created_at => '#{post.created_at}' }])
  end

I'm not developer...

Help me please..

Thanks again!

pollinoco