Rails:在我的show view中,“Next post”和“Previous post”链接如何?
我是Rails新人……微笑
在我的博客应用程序中,我希望在我的节目视图的底部有一个“Previous post”链接和一个“Next post”链接。
我如何做到这一点?
谢谢!
如果每个标题都是唯一的,并且您需要按字母顺序排列,请在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 %>
未经testing,但它应该让你接近。 如果您需要不同的sorting顺序,您可以将title
更改为任何唯一属性( created_at
, id
等)。
我使用了下面的模型方法来避免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
我的方法将允许您自动使用模型范围。 例如,您可能只想显示“已发布”的post。
在你的模型中:
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')
相关的RSpectesting:
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
请注意:当您收到collections中的第一个/最后一个post时,会出现小问题。 我build议视图助手有条件地显示上一个或下一个button,只要它存在。
我就是这么做的 首先,向您的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
请注意使用: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
我相信这可以被重构为不太冗长,但意图是明确的。 很明显,您的标记要求与我的标记要求不同,例如,您可能不会select使用无序列表。
重要的是使用if
语句,因为如果你在第一篇文章,那么他们将不会有以前的post,反之,如果你在最后一篇文章,他们将不会有下一篇文章。
最后,只需从视图中调用帮助器方法:
<%= sidebar_navigation_links %>
试试will_paginate Gem。 它提供了所有你需要分页的条目。 在这里学习
如果您想添加下一个和上一个button,您也可以在这里查看示例代码。
我特别为这种任务创build了gem proximal_records
,它可以在模型中的任何dynamic创build的范围内工作。
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
你真的只需要运行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”是目前的职位。
如果您的post与auto_increment列一起存储,并且您不重复使用ID,则可以使用id列代替created_at – id列已经被编入索引。 如果你想使用created_at列,那么你一定会想在该列上有一个索引。