【问题标题】:Rails 5 previous or next post ONLY from certain tagRails 5 上一个或下一个帖子仅来自特定标签
【发布时间】:2017-10-13 12:41:40
【问题描述】:

我有一个名为帖子的资源,其中有很多。但是,每个帖子可以有多个标签。我希望用户能够仅从选定的标签转到上一篇文章和下一篇文章。我让它适用于上一个下一个数据库中的所有帖子,但是当我单击一个标签并显示所有标签时,上一个/下一个不符合标签是什么。

如果我访问与 routes.rb 中定义的代码相关联的 url,get 'tags/:tag', to: 'posts#index', as: :tag,它将列出索引中的所有标签。我不希望这样,我希望用户能够单击上一个或下一个,并且只在与标签关联的帖子上这样做。

注意:我使用的是friendly_id gem

controllers/posts_controller.rb

  def index
    @posts = Post.all

    if params[:tag]
      @posts = Post.tagged_with(params[:tag])
    else
      @posts = Post.all
    end

  end

models/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

【问题讨论】:

  • but when I click on a tag and it shows all the tags 你能再解释一下吗?它将在哪里显示所有标签?您可以为此添加代码吗?
  • 我已经更新了@NarasimhaReddy 的帖子
  • 所以当一个标签被点击并显示它的相关帖子时,你想要那些帖子列表的分页吗?
  • @arjun 每当点击一个标签并显示相关帖子的列表时,我希望用户点击任何一个帖子并向后或向前移动,但仅限于该标签。 (因此上一个和下一个)。我正在努力让用户一次只能看到一个。

标签: ruby-on-rails ruby


【解决方案1】:

我认为您将不得不传递 tag 参数(尽管您可能应该将其设为辅助方法)

models/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

【讨论】:

  • 你能解释一下发生了什么吗?另外..我收到了这个错误。到底是怎么回事?为model.rb编写的next和tag之间是否应该有空格? ActionController::UrlGenerationError at /posts/1 No route matches {:action=&gt;"show", :controller=&gt;"posts", :id=&gt;nil, :tag=&gt;nil}, possible unmatched constraints: [:id]
  • next 和 tag 之间应该有一个空格,因为它是方法的参数。 (如果你愿意,你可以把它放在括号中,尽管在 ruby​​ 中不需要)。至于错误,我想我在视图中的实现搞砸了。您需要将 id 传递给 url_helper (我想。让我编辑它)。但是,我不确定为什么 tag 参数是 nil。
  • 基本上,。我们正在做的是将每个请求的标签作为current_tag 传递,然后在nextpost 中,我们正在重新评估tagged_with 的范围,current_tag 是争论点。
  • 嘿@Sean,我现在遇到错误:NoMethodError at /posts/hello-world undefined method id' for nil:NilClass` - 我正在使用acts_as_taggablefriendly_id
  • 模型中可能需要self.id 调用。你有那个错误的完整堆栈跟踪吗?
【解决方案2】:

然后你可以把它放在你的控制器中,Post.where(["id &lt; ?", id]).last 用于上一个,Post.where(["id &gt; ?", id]).first 这个用于下一个。

您正在尝试做的是控制器的工作。您可以根据您的排序扩展它们。

我还找到了this gem。用起来会好很多。

【讨论】:

  • 这只是为了发布,我已经有这个功能了。我想要的是上一个或下一个,具体取决于标签。
  • 根据标签是什么意思?
  • 如果用户在帖子控制器中单击上一个或下一个,它工作正常,因为它都在数据库中。但是.. 如果用户点击某个标签,例如“fruits”,如果用户点击“fruits”标签,它应该只显示带有“fruits”标签的帖子。所有帖子都有标签,如果用户点击任何标签,我只想在“上一个和下一个按钮”中显示相关帖子。抱歉,如果之前不清楚
【解决方案3】:

这是肖恩的最新答案。它现在应该可以工作了。当prevnext方法返回nil时出现问题

models/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

附:对不起肖恩,我无法评论你的答案,所以我只是复制并修复它

【讨论】:

  • NameError at /posts/testpost undefined local variable or method `result' for #<0x007fe1538eb9f8>
  • &lt;
【解决方案4】:

您还可以采用嵌套资源方法并像这样更改您的路线:

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

并且将始终显示该标签的帖子。

在帖子控制器的显示操作中,您可以获得下一个和上一个帖子链接,就像上面的答案一样。

您还应该更改视图中使用的所有帖子 url 助手以包含当前标签,例如posts_path -> tag_posts_path(@tag) 其中标签是在 before_filter 中设置的当前标签。

我强烈建议您不要将所有这些方法都放在模型上并为帖子创建演示者对象,例如

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? %>

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-02-11
    • 2020-03-18
    • 1970-01-01
    • 2017-02-20
    • 1970-01-01
    相关资源
    最近更新 更多