Reputation: 1898
My app (Rails 4) allows users to vote on posts. Is it possible to cache the post, but personalise the vote cache so it shows one personalised for current_user? For example, whether the user voted or not.
I would rather not change the html structure to achieve this.
# posts/_post.html.slim
- cache post do
h1 = post.title
= post.text
= render 'votes/form', post: post
# votes/_form.html.slim
- if signed_in? && current_user.voted?(post)
= form_for current_user.votes.find_by(post: post), method: :delete do |f|
= f.submit
- else
= form_for Vote.new do |f|
= f.submit
Upvotes: 5
Views: 1011
Reputation: 1110
Try the following, this will create 2 different fragments for both voted and not voted for each post. It will be read by according to its status.
# posts/_post.html.slim
- cache [post, current_user.votes.find_by(post: post)]do
h1 = post.title
= post.text
= render 'votes/form', post: post
Upvotes: 1
Reputation: 3540
You have two options here:
This is the simplest solution and the one i personally recommends. You just don't cache the dynamic user dependent part so you have something like this:
# posts/_post.html.slim
- cache post do
h1 = post.title
= post.text
= render 'votes/form', post: post # not cached
This solution is more complex, but is actually how basecamp do it (however mostly with more simple examples). You have both part rendered on the page but remove one of them with javascript. Here is a example using jQuery and CoffeeScript:
# posts/_post.html.slim
- cache post do
h1 = post.title
= post.text
= render 'votes/form', post: post
# votes/_form.html.slim
div#votes{"data-id" => post.id}
.not_voted
= form_for current_user.votes.find_by(post: post), method: :delete do |f|
= f.submit
.voted
= form_for Vote.new do |f|
= f.submit
# css
.not_voted {
display:none;
}
# javascript (coffeescript)
jQuery ->
if $('#votes').length
$.getScript('/posts/current/' + $('#votes').data('id'))
# posts_controller.b
def current
@post = Post.find(params[:id])
end
# users/current.js.erb
<% signed_in? && current_user.voted?(@post) %>
$('.voted').hide();
$('.not_voted').show();
<% end %>
I would however properly change voted?
method to accept a id, so you don't need to make a new query. You can learn more about this approach in this railscasts: http://railscasts.com/episodes/169-dynamic-page-caching-revised?view=asciicast
Upvotes: 5