问题
I have the following structure in my rails4 app for the posts. Users can comment on the post and replies can be written on the comments. I'd like to use russian-doll-caching with auto-expiring keys on the page, but I don't know how I should exactly do it in this case.
Can sby tell me how to use it in this case?
Models:
#post.rb
belongs_to :user
has_many :post_comments, dependent: :destroy
#post_comments.rb
belongs_to :user
belongs_to :post
has_many :post_comment_replies, dependent: :destroy
#post_comment_replies.rb
belongs_to :user
belongs_to :post_comments
posts/index.html.erb
<div class="post-index new-post-insert">
<%= render @posts %>
</div>
_post.html.erb
<%= post.body %>
<%= post.user.full_name %>
....
<%= render partial: 'posts/post_comments/post_comment', collection: post.post_comments.ordered.included, as: :post_comment, locals: {post: post} %>
_post_comment.html.erb
<%= post_comment.body %>
<%= post_comment.user.full_name %>
......
<%= render partial: 'posts/post_comment_replies/post_comment_reply', collection: post_comment.post_comment_replies.ordered.included, as: :post_comment_reply, locals: { post_comment: post_comment } %>
_post_comment_reply.html.erb
<%= post_comment_reply.user.full_name %>
<%= post_comment_reply.body %>
回答1:
You need to do a few things
Add touch to your belongs_to
relations
The children and grandchildren of Post
needs to touch their parents so that the updated_at
column updates which in turn invalidates the cache keys.
#post_comments.rb
belongs_to :user
belongs_to :post, touch: true
has_many :post_comment_replies, dependent: :destroy
#post_comment_replies.rb
belongs_to :user
belongs_to :post_comments, touch: true
Add the cache
command to your views
posts/index.html.erb
In the main list of posts we want to cache on the latest updated_at
for posts and the latest updated_at
for the respective user.
<div class="post-index new-post-insert">
<% cache ["posts", @posts.maximum(:updated_at).to_i, @posts.map {|p| p.user.try(:updated_at).to_i}.max] %>
<%= render @posts %>
<% end %>
</div>
_post.html.erb
<% cache ["postlist", post, post.user] %>
<%= post.body %>
<%= post.user.full_name %>
....
<%= render partial: 'posts/post_comments/post_comment', collection: post.post_comments.ordered.included, as: :post_comment, locals: {post: post} %>
<% end %>
_post_comment.html.erb
<% cache ["postcommentlist", post_comment, post_comment.user] %>
<%= post_comment.body %>
<%= post_comment.user.full_name %>
......
<%= render partial: 'posts/post_comment_replies/post_comment_reply', collection: post_comment.post_comment_replies.ordered.included, as: :post_comment_reply, locals: { post_comment: post_comment } %>
<% end %>
_post_comment_reply.html.erb
<% cache ["postcommentreplylist", post_comment_reply, post_comment_reply.user] %>
<%= post_comment_reply.user.full_name %>
<%= post_comment_reply.body %>
<% end %>
This could be improved by using cached: true
in the render partial
function. However since we want to expire the cache if the user changes their username it becomes a bit tricky.
You can do that if you override all the models cache_key
functions.
Why should I use cached: true
in render partial
?
Instead of calling cache
inside each partial (like we do above) we could do
<%= render partial: 'posts/post_comments/post_comment', collection: post.post_comments, cached: true %>
If we only need to cache on the post_comment´s updated_at
.
The difference between the two are that when we cache inside the partial Rails issues a get
command to the cachestore (e.g. memcache) one time per object. Therefore if you have 50 postcomments, there will be 50 separate requests to memcached to retrieve all.
But if we instead use cached: true in the render
call Rails will issue a multi_get
request to memcached and retrieve all 50 objects in one request. Thus improving page loadtime. In tests we have conducted in our production env. it decreased the page loadtime by ~50ms - ~200ms depending on the amount of data.
来源:https://stackoverflow.com/questions/36340017/rails4-double-nested-models-russian-doll-caching