I have a resource named posts, of which there are many. However, each post can have multiple tags. I want users to be able to go to the previous post and next post, ONLY from the tag that was selected. I have it working for all posts from the database in previous next, but when I click on a tag and it shows all the tags, prev/next doesn't adhere to what the tag is.
If I visit the url in association with the code defined in routes.rb, get 'tags/:tag', to: 'posts#index', as: :tag
, it'll list all the tags in an index. I don't want this, I want a user to be able to click previous or next and only do so on posts that are associated with a tag.
Note: I am using the 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
I think you are going to have to pass around that tag
parameter (although you should probably make it a helper method)
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
show
<%= 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' %>
controllers/posts_controller.rb
class PostsController < ApplicationController
helper_method :current_tag
#def show
#def index
private
def current_tag
params[:tag]
end
end
Here is updated Sean's answer. It should work now. The problem appears when prev
or next
methods returning 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
show
<% 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 %>
controllers/posts_controller.rb
class PostsController < ApplicationController
helper_method :current_tag
#def show
#def index
private
def current_tag
params[:tag]
end
end
P.S. sorry Sean, I can't comment on your answer, so I just copied and fixed it
You can put this in your controller then, Post.where(["id < ?", id]).last
for previous and Post.where(["id > ?", id]).first
this for next.
What you are trying to do is the job of the controller. You can extend those based on your sorting.
I also found this gem. Would be much better for you to use.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With