Rails 5 предыдущая или следующая запись ТОЛЬКО из определенного тега

У меня есть ресурс с именем posts, которого много. Однако каждый пост может иметь несколько тегов. Я хочу, чтобы пользователи могли перейти к предыдущему сообщению и следующему сообщению, ТОЛЬКО от выбранного тега. Я работаю над всеми сообщениями из базы данных в предыдущем, но когда я нажимаю на тег, и он показывает все теги, prev/next не придерживается того, что такое тег.

Если я посещу url в сочетании с кодом, определенным в routes.rb, get 'tags/:tag', to: 'posts#index', as: :tag, он перечислит все теги в индексе. Я не хочу этого, я хочу, чтобы пользователь мог нажимать предыдущий или следующий и делать это только на сообщениях, связанных с тегом.

Примечание. Я использую драгоценный камень friendly_id

Контроллеры /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

Ответ 1

Я думаю, вам придется пройти вокруг этого параметра 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

Ответ 2

Вы можете поместить это в свой контроллер, затем Post.where(["id < ?", id]).last для предыдущего и Post.where(["id > ?", id]).first для следующего.

То, что вы пытаетесь сделать, - это задача контроллера. Вы можете расширить их на основе сортировки.

Я также нашел этот камень. Было бы намного лучше для вас.

Ответ 3

Здесь обновляется ответ Шона. Теперь он должен работать. Проблема возникает, когда методы 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. извините, Шон, я не могу прокомментировать ваш ответ, поэтому я просто скопировал и исправил его.

Ответ 4

Вы также можете использовать подход вложенных ресурсов и изменить свои маршруты следующим образом:

resource :tag do
  resource :post
end

Он должен дать вам структуру маршрутов, чтобы /tags/:tag_id/posts указывал на все сообщения для данного тега, а /tags/:tag_id/posts/:id будет указывать на точный пост (или вопрос?), помеченный тегом.

Затем в контроллере сообщений вы должны добавить before_filter :set_tag, как этот

before_filer :set_tag

def set_tag
  @tag = Tag.find(params[:tag_id])
end

действие индекса будет выглядеть следующим образом:

 def index
    @posts = @tag.posts
 end

и всегда будет показывать сообщения для этого тега.

В представлении action-контроллера сообщений вы можете получить следующие и предыдущие ссылки, как в приведенных выше ответах.

Вы также должны изменить все помощники почтового URL, используемые в представлениях, чтобы включить текущий тег, например. posts_pathtag_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? %>