Commit 3c914f5ecb7bf8e6152b28a7b3e8dc79cd98618b

Authored by Moises Machado
Committed by Antonio Terceiro
1 parent a5acd408

ActionItem955: added cache to blocks and friends listing

* basic implementation of cache in blocks
* fixed the timed cache plugin
* polished the cache timeouts
* expiring cache for recent documents and blog archive blocks
* minor performace improvement
* fixed expiring cache of articles
app/controllers/box_organizer_controller.rb
... ... @@ -80,6 +80,7 @@ class BoxOrganizerController < ApplicationController
80 80 def save
81 81 @block = boxes_holder.blocks.find(params[:id])
82 82 @block.update_attributes(params[:block])
  83 + expire_timeout_fragment(@block.cache_keys)
83 84 redirect_to :action => 'index'
84 85 end
85 86  
... ... @@ -90,6 +91,7 @@ class BoxOrganizerController < ApplicationController
90 91 def remove
91 92 @block = Block.find(params[:id])
92 93 if @block.destroy
  94 + expire_timeout_fragment(@block.cache_keys)
93 95 redirect_to :action => 'index'
94 96 else
95 97 flash[:notice] = _('Failed to remove block')
... ...
app/controllers/my_profile/cms_controller.rb
... ... @@ -67,6 +67,7 @@ class CmsController < MyProfileController
67 67 if request.post?
68 68 @article.last_changed_by = user
69 69 if @article.update_attributes(params[:article])
  70 + expire_caches(@article)
70 71 redirect_back
71 72 return
72 73 end
... ... @@ -113,6 +114,7 @@ class CmsController < MyProfileController
113 114 @article.last_changed_by = user
114 115 if request.post?
115 116 if @article.save
  117 + expire_caches(@article)
116 118 redirect_back
117 119 return
118 120 end
... ... @@ -158,6 +160,7 @@ class CmsController < MyProfileController
158 160 def destroy
159 161 @article = profile.articles.find(params[:id])
160 162 if request.post?
  163 + expire_caches(@article)
161 164 @article.destroy
162 165 redirect_to :action => (@article.parent ? 'view' : 'index'), :id => @article.parent
163 166 end
... ... @@ -249,5 +252,11 @@ class CmsController < MyProfileController
249 252 end
250 253 end
251 254  
  255 + def expire_caches(article)
  256 + article.hierarchy.each {|a| expire_fragment(/#{a.cache_key}/) }
  257 + blocks = article.profile.blocks.select{|b|[RecentDocumentsBlock, BlogArchivesBlock].any?{|c| b.kind_of?(c)}}
  258 + blocks.map(&:cache_keys).each{|ck|expire_timeout_fragment(ck)}
  259 + end
  260 +
252 261 end
253 262  
... ...
app/controllers/my_profile/friends_controller.rb
... ... @@ -23,6 +23,7 @@ class FriendsController < MyProfileController
23 23 def remove
24 24 @friend = profile.friends.find(params[:id])
25 25 if request.post? && params[:confirmation]
  26 + expire_fragment(:action => 'friends', :controller => 'profile', :profile => profile.identifier)
26 27 profile.remove_friend(@friend)
27 28 redirect_to :action => 'index'
28 29 end
... ...
app/controllers/public/home_controller.rb
1 1 class HomeController < PublicController
2 2  
3 3 def index
4   - @articles = environment.recent_documents(10)
5 4 end
6 5  
7 6 end
... ...
app/helpers/boxes_helper.rb
... ... @@ -55,6 +55,14 @@ module BoxesHelper
55 55 end
56 56  
57 57 def display_block(block, main_content = nil)
  58 + render :file => 'shared/block', :locals => {:block => block, :main_content => main_content, :use_cache => use_cache? }
  59 + end
  60 +
  61 + def use_cache?
  62 + box_decorator == DontMoveBlocks
  63 + end
  64 +
  65 + def display_block_content(block, main_content = nil)
58 66 content = block.main? ? main_content : block.content
59 67 result = extract_block_content(content)
60 68 footer_content = extract_block_content(block.footer)
... ... @@ -189,12 +197,13 @@ module BoxesHelper
189 197 end
190 198  
191 199 def current_blocks
192   - @controller.boxes_holder.boxes.map(&:blocks).flatten
  200 + @controller.boxes_holder.boxes.map(&:blocks).inject([]){|ac, a| ac + a}
193 201 end
194 202  
195 203 def import_blocks_stylesheets
196   - stylesheet_import( current_blocks.map{|b|'blocks/' + b.css_class_name}.uniq ) + "\n" +
197   - stylesheet_import( current_blocks.map{|b|'blocks/' + b.css_class_name}.uniq, :themed_source => true )
  204 + blocks_css_files = current_blocks.map{|b|'blocks/' + b.css_class_name}.uniq
  205 + stylesheet_import(blocks_css_files) + "\n" +
  206 + stylesheet_import(blocks_css_files, :themed_source => true )
198 207 end
199 208  
200 209 end
... ...
app/models/article.rb
... ... @@ -171,11 +171,11 @@ class Article &lt; ActiveRecord::Base
171 171 end
172 172  
173 173 def url
174   - self.profile.url.merge(:page => path.split('/'))
  174 + @url ||= self.profile.url.merge(:page => path.split('/'))
175 175 end
176 176  
177 177 def view_url
178   - image? ? url.merge(:view => true) : url
  178 + @view_url ||= image? ? url.merge(:view => true) : url
179 179 end
180 180  
181 181 def allow_children?
... ... @@ -254,6 +254,10 @@ class Article &lt; ActiveRecord::Base
254 254 profile
255 255 end
256 256  
  257 + def cache_key
  258 + "article-id-#{id}"
  259 + end
  260 +
257 261 private
258 262  
259 263 def sanitize_tag_list
... ...
app/models/block.rb
... ... @@ -86,4 +86,16 @@ class Block &lt; ActiveRecord::Base
86 86 end
87 87 end
88 88  
  89 + def cacheable?
  90 + true
  91 + end
  92 +
  93 + def cache_keys
  94 + "block-id-#{id}"
  95 + end
  96 +
  97 + def timeout
  98 + 4.hours
  99 + end
  100 +
89 101 end
... ...
app/models/login_block.rb
... ... @@ -18,4 +18,8 @@ class LoginBlock &lt; Block
18 18 end
19 19 end
20 20  
  21 + def cacheable?
  22 + false
  23 + end
  24 +
21 25 end
... ...
app/models/main_block.rb
... ... @@ -20,4 +20,8 @@ class MainBlock &lt; Block
20 20 false
21 21 end
22 22  
  23 + def cacheable?
  24 + false
  25 + end
  26 +
23 27 end
... ...
app/models/my_network_block.rb
... ... @@ -24,4 +24,8 @@ class MyNetworkBlock &lt; Block
24 24 end
25 25 end
26 26  
  27 + def cacheable?
  28 + false
  29 + end
  30 +
27 31 end
... ...
app/models/profile.rb
... ... @@ -326,7 +326,7 @@ class Profile &lt; ActiveRecord::Base
326 326 end
327 327  
328 328 def url
329   - if self.domains.empty?
  329 + @url ||= if self.domains.empty?
330 330 generate_url(:controller => 'content_viewer', :action => 'view_page', :page => [])
331 331 else
332 332 Noosfero.url_options.merge({ :host => self.domains.first.name, :controller => 'content_viewer', :action => 'view_page', :page => []})
... ...
app/models/profile_image_block.rb
... ... @@ -19,4 +19,8 @@ class ProfileImageBlock &lt; Block
19 19 false
20 20 end
21 21  
  22 + def cacheable?
  23 + false
  24 + end
  25 +
22 26 end
... ...
app/models/profile_info_block.rb
... ... @@ -19,4 +19,8 @@ class ProfileInfoBlock &lt; Block
19 19 false
20 20 end
21 21  
  22 + def cacheable?
  23 + false
  24 + end
  25 +
22 26 end
... ...
app/models/recent_documents_block.rb
... ... @@ -32,4 +32,8 @@ class RecentDocumentsBlock &lt; Block
32 32 end
33 33 end
34 34  
  35 + def timeout
  36 + 2.months
  37 + end
  38 +
35 39 end
... ...
app/models/tags_block.rb
... ... @@ -29,4 +29,8 @@ class TagsBlock &lt; Block
29 29 "\n</div><!-- end class='tag_cloud' -->\n";
30 30 end
31 31  
  32 + def timeout
  33 + 15.minutes
  34 + end
  35 +
32 36 end
... ...
app/views/content_viewer/view_page.rhtml
... ... @@ -83,10 +83,12 @@
83 83 </div>
84 84 <% end %>
85 85  
86   -<div class="<%="article-body article-body-" + @page.css_class_name %>">
87   - <%= article_to_html(@page) %>
88   - <br style="clear:both" />
89   -</div> <!-- end class="article-body" -->
  86 +<% cache(@page.cache_key) do %>
  87 + <div class="<%="article-body article-body-" + @page.css_class_name %>">
  88 + <%= article_to_html(@page) %>
  89 + <br style="clear:both" />
  90 + </div> <!-- end class="article-body" -->
  91 +<% end %>
90 92  
91 93 <% if ! @page.categories.empty? %>
92 94 <div id="article-cat">
... ...
app/views/profile/friends.rhtml
... ... @@ -3,11 +3,13 @@
3 3  
4 4 <h1><%= __("%s's friends") % profile.name %></h1>
5 5  
  6 +<% cache do%>
6 7 <ul class='profile-list'>
7 8 <% @friends.each do |friend| %>
8 9 <li><%= profile_image_link(friend) %></li>
9 10 <% end%>
10 11 </ul>
  12 +<% end %>
11 13  
12 14 <% button_bar do %>
13 15 <% if user == profile %>
... ...
app/views/shared/block.rhtml 0 → 100644
... ... @@ -0,0 +1,7 @@
  1 +<% if block.cacheable? && use_cache %>
  2 + <% cache_timeout(block.cache_keys, block.timeout.from_now) do %>
  3 + <%= display_block_content(block, main_content) %>
  4 + <% end %>
  5 +<% else %>
  6 + <%= display_block_content(block, main_content) %>
  7 +<% end %>
... ...
test/unit/block_test.rb
... ... @@ -54,4 +54,17 @@ class BlockTest &lt; Test::Unit::TestCase
54 54 assert !b.visible?
55 55 end
56 56  
  57 + should 'be cacheable' do
  58 + b = Block.new
  59 + assert b.cacheable?
  60 + end
  61 +
  62 + should 'provide chache keys' do
  63 + p = create_user('test_user').person
  64 + box = p.boxes[0]
  65 + b = Block.create!(:box => box)
  66 +
  67 + assert_equal( "block-id-#{b.id}", b.cache_keys)
  68 + end
  69 +
57 70 end
... ...
vendor/plugins/timed_cached_fragment/lib/timed_cache_fragment.rb
... ... @@ -17,12 +17,12 @@ module ActionController
17 17 #handles the expiration of timeout fragment
18 18 def expire_timeout_fragment(key)
19 19 @@cache_timeout_values[key] = nil
20   - expire_fragment(key)
  20 + expire_fragment(/#{key}/)
21 21 end
22 22 #checks to see if a cache has fully expired
23 23 def is_cache_expired?(name, is_key = false)
24   - key = is_key ? fragment_cache_key(name) : name
25   - return (!@@cache_timeout_values.has_key?(key)) || (@@cache_timeout_values[key] < Time.now)
  24 + key = is_key ? name : fragment_cache_key(name)
  25 + return (!@@cache_timeout_values[key]) || (@@cache_timeout_values[key] < Time.now)
26 26 end
27 27 end
28 28 end
... ... @@ -46,4 +46,4 @@ end
46 46  
47 47 #add to the respective controllers
48 48 ActionView::Base.send(:include, ActionView::Helpers::TimedCacheHelper)
49   -ActionController::Base.send(:include, ActionController::Cache::TimedCache)
50 49 \ No newline at end of file
  50 +ActionController::Base.send(:include, ActionController::Cache::TimedCache)
... ...