Reputation: 743
I have a model where a user can enter a multiple choice question. I have a view where a user can click "previous" or "next", and it takes them up 1 or down 1 in the database.
However, I want to make it so that..
A. User clicks on "next", is taken to a new random question that hasn't been viewed before.
B. User clicks on "prev", is taken to the last question that was done, and the last question done before that.
C. User should have different order of "next" as compared to other users.
How can I go about doing this?
post.rb
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
posts_controller.rb
def show
@post = Post.friendly.find(params[:id])
# this is used in the show.html.erb view for posts
@randomize_posts = [
@post.answer_choice,
@post.answer_choice_2,
@post.answer_choice_3,
@post.answer_choice_4,
@post.answer_choice_5
].shuffle
end
posts/show.html.erb
<%= link_to "← Previous Question", @post.prev, :class => 'button previous-question' %>
<%= link_to "Next Question →", @post.next, :class => 'button next-question' %>
Upvotes: 0
Views: 141
Reputation: 2950
There are a few ways of doing this. I'd recommend doing a deterministic approach where different users get different results, but the same user will always have the same result. This allows for you to have randomness and do forward/backward navigation without storing extra data.
To randomize on a deterministic way, you can apply an md5
method on the post's id and the current user id:
posts = Post.order("md5('#{current_user.id}' || posts.id::text)")
Now the simplest way of finding the next and the previous is to see which one is right after and before the current one. You know the current one's position by calculating its md5
hash, so you just need to find which one comes right after or right before:
Post
.where("md5('?' || '?') > md5('?' || posts.id::text)", current_user.id, id, current_user.id)
.order("md5('#{current_user.id}' || posts.id::text)")
.limit(1)
Applying to your model, it could look something like:
def next(user)
ordered_posts(user)
.where("md5('?' || '?') > md5('?' || posts.id::text)", user.id, id, user.id)
end
def prev(user)
ordered_posts(user)
.where("md5('?' || '?') < md5('?' || posts.id::text)", user.id, id, user.id)
end
private
def ordered_posts(user)
Post.order("md5('#{current_user.id}' || posts.id::text)")
end
And the view would look like:
<%= link_to "← Previous Question", @post.prev(current_user), :class => 'button previous-question' %>
<%= link_to "Next Question →", @post.next(current_user), :class => 'button next-question' %>
Upvotes: 2