Rails:我的节目视图中的“下一篇文章”和“上一篇文章”链接,如何?

时间:2009-08-14 03:54:29

标签: ruby-on-rails

我是Rails的新手......微笑

在我的博客中,我希望在展示视图的底部有一个“上一篇文章”链接和一个“下一篇文章”链接。

我该怎么做?

谢谢!

7 个答案:

答案 0 :(得分:42)

如果每个标题都是唯一的,并且您需要按字母顺序排列,请在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

然后,您可以链接到视图中的那些。

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

未经测试,但它应该让你接近。如果您需要不同的排序顺序,可以将title更改为任何唯一属性(created_atid等)。

答案 1 :(得分:13)

我使用下面的模型方法来避免id + 1不存在而id + 2存在的问题。

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

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

在我的视图代码中,我只是这样做:

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

答案 2 :(得分:4)

我的方法将允许您自动使用模型范围。例如,您可能只想显示“已发布”的帖子。

在你的模特中:

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

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

在你看来

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

在您的控制器中

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

相关的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

注意:当您到达集合中的第一篇/最后一篇文章时会出现小问题。我推荐一个视图帮助器,只有当它存在时才有条件地显示上一个或下一个按钮。

答案 3 :(得分:1)

这就是我做的。首先,在您的Post模型中添加几个named scopes

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

请注意使用:select选项来限制字段,因为您可能不想仅仅为了显示链接而检索完全填充的Post实例。

然后在我的posts_helper我有这个方法:

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

我确信这可以重构为不那么冗长,但目的很明确。显然,您的标记要求与我的不同,因此您可能不会选择使用无序列表。

重要的是使用if陈述,因为如果你在第一篇文章上,那么他们将不会发布任何帖子,相反,如果你在最后一篇文章中,他们将不会下一篇文章。

最后,只需从您的视图中调用辅助方法:

<%= sidebar_navigation_links %>

答案 4 :(得分:0)

尝试will_paginate宝石。它提供了对帖子条目进行分页所需的所有功能。学习here

如果您想要添加下一个和上一个按钮,也可以查看here示例代码。

答案 5 :(得分:0)

我已经创建了gem proximal_records,特别是对于这种任务,它适用于模型中任何动态创建的范围。

https://github.com/dmitry/proximal_records

基本示例:

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

答案 6 :(得分:-1)

你真的只需要运行2个查询,每个查询分别为“prev”和“next”。让我们假设您有一个created_at列。

伪代码:

# 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

当然“this_post”是当前的帖子。

如果您的帖子存储了auto_increment列并且您不重复使用ID,则可以使用id列代替created_at - id列应该已经编入索引。如果你想使用created_at列,那么你肯定希望在该列上有一个索引。