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