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,6 +80,7 @@ class BoxOrganizerController < ApplicationController
80 def save 80 def save
81 @block = boxes_holder.blocks.find(params[:id]) 81 @block = boxes_holder.blocks.find(params[:id])
82 @block.update_attributes(params[:block]) 82 @block.update_attributes(params[:block])
  83 + expire_timeout_fragment(@block.cache_keys)
83 redirect_to :action => 'index' 84 redirect_to :action => 'index'
84 end 85 end
85 86
@@ -90,6 +91,7 @@ class BoxOrganizerController < ApplicationController @@ -90,6 +91,7 @@ class BoxOrganizerController < ApplicationController
90 def remove 91 def remove
91 @block = Block.find(params[:id]) 92 @block = Block.find(params[:id])
92 if @block.destroy 93 if @block.destroy
  94 + expire_timeout_fragment(@block.cache_keys)
93 redirect_to :action => 'index' 95 redirect_to :action => 'index'
94 else 96 else
95 flash[:notice] = _('Failed to remove block') 97 flash[:notice] = _('Failed to remove block')
app/controllers/my_profile/cms_controller.rb
@@ -67,6 +67,7 @@ class CmsController < MyProfileController @@ -67,6 +67,7 @@ class CmsController < MyProfileController
67 if request.post? 67 if request.post?
68 @article.last_changed_by = user 68 @article.last_changed_by = user
69 if @article.update_attributes(params[:article]) 69 if @article.update_attributes(params[:article])
  70 + expire_caches(@article)
70 redirect_back 71 redirect_back
71 return 72 return
72 end 73 end
@@ -113,6 +114,7 @@ class CmsController < MyProfileController @@ -113,6 +114,7 @@ class CmsController < MyProfileController
113 @article.last_changed_by = user 114 @article.last_changed_by = user
114 if request.post? 115 if request.post?
115 if @article.save 116 if @article.save
  117 + expire_caches(@article)
116 redirect_back 118 redirect_back
117 return 119 return
118 end 120 end
@@ -158,6 +160,7 @@ class CmsController < MyProfileController @@ -158,6 +160,7 @@ class CmsController < MyProfileController
158 def destroy 160 def destroy
159 @article = profile.articles.find(params[:id]) 161 @article = profile.articles.find(params[:id])
160 if request.post? 162 if request.post?
  163 + expire_caches(@article)
161 @article.destroy 164 @article.destroy
162 redirect_to :action => (@article.parent ? 'view' : 'index'), :id => @article.parent 165 redirect_to :action => (@article.parent ? 'view' : 'index'), :id => @article.parent
163 end 166 end
@@ -249,5 +252,11 @@ class CmsController < MyProfileController @@ -249,5 +252,11 @@ class CmsController < MyProfileController
249 end 252 end
250 end 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 end 261 end
253 262
app/controllers/my_profile/friends_controller.rb
@@ -23,6 +23,7 @@ class FriendsController < MyProfileController @@ -23,6 +23,7 @@ class FriendsController < MyProfileController
23 def remove 23 def remove
24 @friend = profile.friends.find(params[:id]) 24 @friend = profile.friends.find(params[:id])
25 if request.post? && params[:confirmation] 25 if request.post? && params[:confirmation]
  26 + expire_fragment(:action => 'friends', :controller => 'profile', :profile => profile.identifier)
26 profile.remove_friend(@friend) 27 profile.remove_friend(@friend)
27 redirect_to :action => 'index' 28 redirect_to :action => 'index'
28 end 29 end
app/controllers/public/home_controller.rb
1 class HomeController < PublicController 1 class HomeController < PublicController
2 2
3 def index 3 def index
4 - @articles = environment.recent_documents(10)  
5 end 4 end
6 5
7 end 6 end
app/helpers/boxes_helper.rb
@@ -55,6 +55,14 @@ module BoxesHelper @@ -55,6 +55,14 @@ module BoxesHelper
55 end 55 end
56 56
57 def display_block(block, main_content = nil) 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 content = block.main? ? main_content : block.content 66 content = block.main? ? main_content : block.content
59 result = extract_block_content(content) 67 result = extract_block_content(content)
60 footer_content = extract_block_content(block.footer) 68 footer_content = extract_block_content(block.footer)
@@ -189,12 +197,13 @@ module BoxesHelper @@ -189,12 +197,13 @@ module BoxesHelper
189 end 197 end
190 198
191 def current_blocks 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 end 201 end
194 202
195 def import_blocks_stylesheets 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 end 207 end
199 208
200 end 209 end
app/models/article.rb
@@ -171,11 +171,11 @@ class Article &lt; ActiveRecord::Base @@ -171,11 +171,11 @@ class Article &lt; ActiveRecord::Base
171 end 171 end
172 172
173 def url 173 def url
174 - self.profile.url.merge(:page => path.split('/')) 174 + @url ||= self.profile.url.merge(:page => path.split('/'))
175 end 175 end
176 176
177 def view_url 177 def view_url
178 - image? ? url.merge(:view => true) : url 178 + @view_url ||= image? ? url.merge(:view => true) : url
179 end 179 end
180 180
181 def allow_children? 181 def allow_children?
@@ -254,6 +254,10 @@ class Article &lt; ActiveRecord::Base @@ -254,6 +254,10 @@ class Article &lt; ActiveRecord::Base
254 profile 254 profile
255 end 255 end
256 256
  257 + def cache_key
  258 + "article-id-#{id}"
  259 + end
  260 +
257 private 261 private
258 262
259 def sanitize_tag_list 263 def sanitize_tag_list
app/models/block.rb
@@ -86,4 +86,16 @@ class Block &lt; ActiveRecord::Base @@ -86,4 +86,16 @@ class Block &lt; ActiveRecord::Base
86 end 86 end
87 end 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 end 101 end
app/models/login_block.rb
@@ -18,4 +18,8 @@ class LoginBlock &lt; Block @@ -18,4 +18,8 @@ class LoginBlock &lt; Block
18 end 18 end
19 end 19 end
20 20
  21 + def cacheable?
  22 + false
  23 + end
  24 +
21 end 25 end
app/models/main_block.rb
@@ -20,4 +20,8 @@ class MainBlock &lt; Block @@ -20,4 +20,8 @@ class MainBlock &lt; Block
20 false 20 false
21 end 21 end
22 22
  23 + def cacheable?
  24 + false
  25 + end
  26 +
23 end 27 end
app/models/my_network_block.rb
@@ -24,4 +24,8 @@ class MyNetworkBlock &lt; Block @@ -24,4 +24,8 @@ class MyNetworkBlock &lt; Block
24 end 24 end
25 end 25 end
26 26
  27 + def cacheable?
  28 + false
  29 + end
  30 +
27 end 31 end
app/models/profile.rb
@@ -326,7 +326,7 @@ class Profile &lt; ActiveRecord::Base @@ -326,7 +326,7 @@ class Profile &lt; ActiveRecord::Base
326 end 326 end
327 327
328 def url 328 def url
329 - if self.domains.empty? 329 + @url ||= if self.domains.empty?
330 generate_url(:controller => 'content_viewer', :action => 'view_page', :page => []) 330 generate_url(:controller => 'content_viewer', :action => 'view_page', :page => [])
331 else 331 else
332 Noosfero.url_options.merge({ :host => self.domains.first.name, :controller => 'content_viewer', :action => 'view_page', :page => []}) 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,4 +19,8 @@ class ProfileImageBlock &lt; Block
19 false 19 false
20 end 20 end
21 21
  22 + def cacheable?
  23 + false
  24 + end
  25 +
22 end 26 end
app/models/profile_info_block.rb
@@ -19,4 +19,8 @@ class ProfileInfoBlock &lt; Block @@ -19,4 +19,8 @@ class ProfileInfoBlock &lt; Block
19 false 19 false
20 end 20 end
21 21
  22 + def cacheable?
  23 + false
  24 + end
  25 +
22 end 26 end
app/models/recent_documents_block.rb
@@ -32,4 +32,8 @@ class RecentDocumentsBlock &lt; Block @@ -32,4 +32,8 @@ class RecentDocumentsBlock &lt; Block
32 end 32 end
33 end 33 end
34 34
  35 + def timeout
  36 + 2.months
  37 + end
  38 +
35 end 39 end
app/models/tags_block.rb
@@ -29,4 +29,8 @@ class TagsBlock &lt; Block @@ -29,4 +29,8 @@ class TagsBlock &lt; Block
29 "\n</div><!-- end class='tag_cloud' -->\n"; 29 "\n</div><!-- end class='tag_cloud' -->\n";
30 end 30 end
31 31
  32 + def timeout
  33 + 15.minutes
  34 + end
  35 +
32 end 36 end
app/views/content_viewer/view_page.rhtml
@@ -83,10 +83,12 @@ @@ -83,10 +83,12 @@
83 </div> 83 </div>
84 <% end %> 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 <% if ! @page.categories.empty? %> 93 <% if ! @page.categories.empty? %>
92 <div id="article-cat"> 94 <div id="article-cat">
app/views/profile/friends.rhtml
@@ -3,11 +3,13 @@ @@ -3,11 +3,13 @@
3 3
4 <h1><%= __("%s's friends") % profile.name %></h1> 4 <h1><%= __("%s's friends") % profile.name %></h1>
5 5
  6 +<% cache do%>
6 <ul class='profile-list'> 7 <ul class='profile-list'>
7 <% @friends.each do |friend| %> 8 <% @friends.each do |friend| %>
8 <li><%= profile_image_link(friend) %></li> 9 <li><%= profile_image_link(friend) %></li>
9 <% end%> 10 <% end%>
10 </ul> 11 </ul>
  12 +<% end %>
11 13
12 <% button_bar do %> 14 <% button_bar do %>
13 <% if user == profile %> 15 <% if user == profile %>
app/views/shared/block.rhtml 0 → 100644
@@ -0,0 +1,7 @@ @@ -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,4 +54,17 @@ class BlockTest &lt; Test::Unit::TestCase
54 assert !b.visible? 54 assert !b.visible?
55 end 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 end 70 end
vendor/plugins/timed_cached_fragment/lib/timed_cache_fragment.rb
@@ -17,12 +17,12 @@ module ActionController @@ -17,12 +17,12 @@ module ActionController
17 #handles the expiration of timeout fragment 17 #handles the expiration of timeout fragment
18 def expire_timeout_fragment(key) 18 def expire_timeout_fragment(key)
19 @@cache_timeout_values[key] = nil 19 @@cache_timeout_values[key] = nil
20 - expire_fragment(key) 20 + expire_fragment(/#{key}/)
21 end 21 end
22 #checks to see if a cache has fully expired 22 #checks to see if a cache has fully expired
23 def is_cache_expired?(name, is_key = false) 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 end 26 end
27 end 27 end
28 end 28 end
@@ -46,4 +46,4 @@ end @@ -46,4 +46,4 @@ end
46 46
47 #add to the respective controllers 47 #add to the respective controllers
48 ActionView::Base.send(:include, ActionView::Helpers::TimedCacheHelper) 48 ActionView::Base.send(:include, ActionView::Helpers::TimedCacheHelper)
49 -ActionController::Base.send(:include, ActionController::Cache::TimedCache)  
50 \ No newline at end of file 49 \ No newline at end of file
  50 +ActionController::Base.send(:include, ActionController::Cache::TimedCache)