问题
I know dalli
(caching) is pretty powerful plugin to enhance performance for static pages.
But what about dynamic pages with pagination, which are updated quite often?
What is the correct way to set up dalli
?
One problem I've encountered for example: dalli
recognizes different params[:page] as the same page when using pagination:(
How would you guys design the system when using dalli
for both
- the page that gets updated so often
- the page that won't be updated so often
For example. I have 4 models such as User
, Community
, Topic
, and Comment(defined Polymorphic to both Community, and Topic. They can be created or shown in #show pages)
It's like
- Community > (has_many) > Topics > (has_many) > Comments
- Community > (has_many) > Comments
- All of them belongs to user(creator)
My current codes are just like this(This is quite bit long. Sorry about that)
I'm facing the pagination problem when using caching...
-------------------------------------Settings----------------------------------------
config/environments/development.rb
config.consider_all_requests_local = true
config.action_controller.perform_caching = true
config.cache_store = :dalli_store
routes.rb
resources :communities do
resources :topics do
resources :comments do
end
end
-------------------------------------Community----------------------------------------
controllers/communities_controller.rb#index&show
caches_page :show
caches_action :edit, :new
def index
....
if params[:sort] == 'new'
@communities = Community.scoped.page(params[:page]).order("created_at DESC")
elsif params[:sort] = 'popular'
@communities = Community.scoped.page(params[:page]).order("follow_count DESC")
elsif params[:sort] = 'reputation'
@communities = Community.scoped.page(params[:page]).order("reputation_count DESC")
else
@communities = Community.scoped.page(params[:page]).order("created_at DESC")
end
....
end
def show
@community = Community.find(params[:community_id])
@comments @community.comments.page(params[:page]
@topics = @community.topics.limit(10)
end
views/communities/index.html.erb note: However, the content will be the same even if I move to next params[:page]:( It seems caching recognize different page as the same contents...
#here, the url will could be something like this example.com/communities?utf8=✓&location=14&genre=3&search=strawberry
But this is going to create gigantic petterns of the caches:(
So I want to make it work only when params[:sort] was not empty. Because, no other parameters come with when params[:sort] is not empty.
It could be like, example.com/communities?sort=new, example.com/communities?sort=popular, example.com/communities?sort=reputation
...
<% if params[:sort] %>
<% @key = "community_index_" + params[:sort] + params[:page] %>
<% cache(:controller => "communities", :action => "index", :action_suffix => @key) do %>
<%= page_entries_info(@communities, :entry_name => 'community').html_safe %>
<%= paginate @communities, :window => 4 %>
<% @communities.each do |community| %>
<%= render 'communities/community', :community => community %>
<% end %>
<% end %>
<% end %>
...
views/communities/show.html.erb
...
<% @key = params[:community_name] + "_community_show_information" %>
<% cache(:controller => "communities", :action => "show", :action_suffix => @key) do %>
<h2>Information</h2>
<div class="CommunityInformation">
<%= render 'communities/information'%>
</div>
<% end %>
<% @key = params[:community_name] + "_community_show_wall_" + params[:page] + %>
<% cache(:controller => "communities", :action => "show", :action_suffix => @key) do %>
<%= paginate @comments, :window => 4 %>
<h2>Topic</h2>
<div class="WallInformation">
<% @comments.eager.recent.each do |comment| %>
<%= render 'communities/comment', :comment => comment %>
<% end %>
</div>
<% end %>
<% @key = params[:community_name] + "_community_show_topics" %>
<% cache(:controller => "communities", :action => "show", :action_suffix => @key) do %>
<h2>Topic</h2>
<div class="TopicInformation">
<% @topics.eager.recent.each do |topic| %>
<%= render 'communities/topic', :topic => topic %>
<% end %>
</div>
<% end %>
...
models/community_sweeper.rb
class CommunitySweeper < ActionController::Caching::Sweeper
observe Community
def after_save(record)
expire_fragment(url_for(:action => 'index', :only_path => true) + '?????(all the caches related to the community#index)')
expire_fragment(url_for(:action => 'show', :only_path => true) + '?????(the cache related to the particular community#show)')
end
end
end
-------------------------------------Topic----------------------------------------
controllers/topics_controller.rb#index&show
caches_page :show
caches_action :edit, :new
def index
....
@community = Community.find(params[:community_id])
@topics = @community.topics.page(params[:page]
....
end
def show
@topic = Topic.find(params[:id])
@comments = @topic.comments.page(params[:page]
end
views/topics/index.html.erb
...
<% @key = params[:community_id] + "_topic_index_" + params[:page] %>
<% cache(:controller => "topics", :action => "index", :action_suffix => @key) do %>
<%= page_entries_info(@communities, :entry_name => 'community').html_safe %>
<%= paginate @communities, :window => 4 %>
<% @communities.each do |community| %>
<%= render 'communities/community', :community => community %>
<% end %>
<% end %>
<% end %>
...
views/topics/show.html.erb
...
<% @key = params[:community_name] + "_topic_show_" + params[:id] + "_comments" + params[:page] %>
<% cache(:controller => "topics", :action => "show", :action_suffix => @key) do %>
<%= paginate @comments, :window => 4 %>
<%= page_entries_info(@comments, :entry_name => 'comment').html_safe %>
<h2>Comment</h2>
<div class="CommentInformation">
<% @comments.each do |comment| %>
<%= render 'topics/comment', :comment => comment %>
<% end %>
</div>
<% end %>
...
models/topic_sweeper.rb
class TopicSweeper < ActionController::Caching::Sweeper
observe Topic
def after_save(record)
expire_fragment(url_for(:action => 'index', :only_path => true) + '?????(all the caches related to the topic#index)')
expire_fragment(url_for(:action => 'show', :only_path => true) + '?????(the cache related to the particular topic#show)')
end
end
-------------------------------------Comment----------------------------------------
models/comment_sweeper.rb
class CommentSweeper < ActionController::Caching::Sweeper
observe Comment
def after_save(record)
expire_fragment(url_for(:action => 'index', :only_path => true) + '?????(all the caches related to the topic#index)')
expire_fragment(url_for(:action => 'show', :only_path => true) + '?????(the cache related to the particular topic#show)')
end
end
回答1:
I am following on on from my answer to
How should I set up dalli for a dynamic page with lots of content updates?
Please note that I am not an expert but I did try your approach and abandoned it as it just kept getting more and more complex as my application grew and I went for the cache key fragment based approach mentioned in the last question. There are a few things to bear in mind.
The cache sweeper approach requires you to make sure that the sweeper is up to date as you make changes to your application which means extra maintenance and testing work.
In a dynamic application you probably wont be able to easily cache whole pages especially if the views show information from many models.
You wont be able to deal with the paging issue unless the page parameter becomes part of your cache keys.
When your cache gets full, memcached will simply remove the least used / oldest cache items when putting in a new cache fragment.
So there is no issue with you just pushing in a new cache fragments when your models change and letting memcached clear out the old out of date cache items.
Therefore fragment caching in your views will probably be the easiest solution as it will deal with paging and you wont have to deal with manual cache invalidation
So looking at one of your views, what I might do is
<% if params[:sort] %>
<%= page_entries_info(@communities, :entry_name => 'community').html_safe %>
<%= paginate @communities, :window => 4 %>
<% @communities.each do |community| %>
<% cache(community, :suffix => "community_index") do
<%= render 'communities/community', :community => community %>
<% end %>
<% end %>
<% end %>
What I have done is cache the rendering of each community record and paging becomes irrelavent
来源:https://stackoverflow.com/questions/14544396/how-can-i-implement-fragment-cache-with-dalli-when-using-pagination-kaminari