我有一个名为posts的资源,其中有很多。但是,每个帖子可以有多个标签。我希望用户能够从所选的标签转到上一篇文章和下一篇文章。我让它适用于前一个数据库中的所有帖子,但当我点击一个标签并显示所有标签时,prev / next不符合标签的内容。
如果我访问与routes.rb get 'tags/:tag', to: 'posts#index', as: :tag
中定义的代码相关联的url,它将列出索引中的所有标记。我不希望这样,我希望用户能够单击上一个或下一个,并且仅对与标签关联的帖子执行此操作。
注意:我使用的是friendly_id gem
控制器/ posts_controller.rb
def index
@posts = Post.all
if params[:tag]
@posts = Post.tagged_with(params[:tag])
else
@posts = Post.all
end
end
模型/ post.rb
# tags
acts_as_taggable # Alias for acts_as_taggable_on :tags
def next
Post.where("id > ?", id).order(id: :asc).limit(1).first
end
def prev
Post.where("id < ?", id).order(id: :desc).limit(1).first
end
show.html.erb
<%= link_to "← Previous Question", @post.prev, :class => 'button previous-question' %>
<%= link_to "Next Question →", @post.next, :class => 'button next-question' %>
的routes.rb
# TAGS
get 'tags/:tag', to: 'posts#index', as: :tag
答案 0 :(得分:7)
我认为你将不得不传递tag
参数(尽管你应该把它作为辅助方法)
模型/ post.rb
def next tag
Post.where("id > ?", id).tagged_with(tag).order(id: :asc).limit(1).first
end
def prev tag
Post.where("id < ?", id).tagged_with(tag).order(id: :desc).limit(1).first
end
显示
<%= link_to "← Previous Question", post_path(@post.prev(current_tag).id, tag: current_tag), :class => 'button previous-question' %>
<%= link_to "Next Question →", post_path(@post.next(current_tag).id, tag: current_tag), :class => 'button next-question' %>
控制器/ posts_controller.rb
class PostsController < ApplicationController
helper_method :current_tag
#def show
#def index
private
def current_tag
params[:tag]
end
end
答案 1 :(得分:4)
您可以将它放在您的控制器中,然后Post.where(["id < ?", id]).last
表示前一个,Post.where(["id > ?", id]).first
表示下一个。
您要做的是控制器的工作。您可以根据排序扩展它们。
我还找到了this gem。对你来说会更好用。
答案 2 :(得分:4)
这是Sean的回答。它现在应该工作。当prev
或next
方法返回nil
模型/ post.rb
def next tag
result = Post.where("id > ?", id).tagged_with(tag).order(id: :asc).limit(1).first
result || very_first(tag)
end
def prev tag
result = Post.where("id < ?", id).tagged_with(tag).order(id: :desc).limit(1).first
result || very_last(tag)
end
def very_first tag
Post.tagged_with(tag).order(id: :asc).limit(1).first
end
def very_last tag
Post.tagged_with(tag).order(id: :asc).limit(1).last
end
显示
<% if @post.prev(current_tag) %>
<%= link_to "← Previous Question", post_path(@post.prev(current_tag).id, tag: current_tag), :class => 'button previous-question' %>
<% end %>
<% if @post.next(current_tag) %>
<%= link_to "Next Question →", post_path(@post.next(current_tag).id, tag: current_tag), :class => 'button next-question' %>
<% end %>
控制器/ posts_controller.rb
class PostsController < ApplicationController
helper_method :current_tag
#def show
#def index
private
def current_tag
params[:tag]
end
end
P.S。对不起肖恩,我无法对你的答案发表评论,所以我只是复制并修复了它
答案 3 :(得分:3)
您还可以采用嵌套资源方法并更改您的路线,如下所示:
resource :tag do
resource :post
end
它应该为您提供路由结构,以便/tags/:tag_id/posts
指向给定标记的所有帖子,/tags/:tag_id/posts/:id
将指向标记有该标记的确切帖子(或问题?)。
然后在posts控制器中,你应该像这样添加before_filter :set_tag
before_filer :set_tag
def set_tag
@tag = Tag.find(params[:tag_id])
end
索引操作看起来像这样
def index
@posts = @tag.posts
end
并始终显示该标记的帖子。
在帖子控制器的show动作中,您可以获得下一个和上一个帖子链接,就像上面的答案一样。
您还应该更改视图中使用的所有帖子网址助手,以包含当前标记,例如posts_path
- &gt; tag_posts_path(@tag)
其中tag是在before_filter中设置的当前标记。
我强烈建议您不要将所有这些方法放在模型上,并为帖子创建一个presenter对象,例如
class PostPresenter
attr_reader :post
alias_method :current, :post
def initialize(post)
@post = post
@repo = post.class
end
def next
@repo.where('id > ?', post.id).first
end
def previous
@repo.where('id < ?', post.id).first
end
end
和
@presenter = PostPresenter.new(@post)
以及下一篇文章的链接
<%= link_to "Next Question →",
tag_post_path(@presenter.next),
class: 'button next-question' if @presenter.next.present? %>