rails_csi 2.3.5.p6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (320) hide show
  1. data/CHANGELOG +2172 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README +243 -0
  4. data/Rakefile +368 -0
  5. data/bin/about +4 -0
  6. data/bin/console +3 -0
  7. data/bin/dbconsole +3 -0
  8. data/bin/destroy +3 -0
  9. data/bin/generate +3 -0
  10. data/bin/performance/benchmarker +3 -0
  11. data/bin/performance/profiler +3 -0
  12. data/bin/plugin +3 -0
  13. data/bin/rails +20 -0
  14. data/bin/runner +3 -0
  15. data/bin/server +3 -0
  16. data/builtin/rails_info/rails/info.rb +131 -0
  17. data/builtin/rails_info/rails/info_controller.rb +9 -0
  18. data/builtin/rails_info/rails/info_helper.rb +2 -0
  19. data/builtin/rails_info/rails_info_controller.rb +2 -0
  20. data/configs/databases/frontbase.yml +28 -0
  21. data/configs/databases/ibm_db.yml +62 -0
  22. data/configs/databases/mysql.yml +60 -0
  23. data/configs/databases/oracle.yml +39 -0
  24. data/configs/databases/postgresql.yml +51 -0
  25. data/configs/databases/sqlite2.yml +19 -0
  26. data/configs/databases/sqlite3.yml +22 -0
  27. data/configs/empty.log +0 -0
  28. data/configs/initializers/backtrace_silencers.rb +7 -0
  29. data/configs/initializers/inflections.rb +10 -0
  30. data/configs/initializers/mime_types.rb +5 -0
  31. data/configs/initializers/new_rails_defaults.rb +21 -0
  32. data/configs/initializers/session_store.rb +15 -0
  33. data/configs/locales/en.yml +5 -0
  34. data/configs/routes.rb +43 -0
  35. data/configs/seeds.rb +7 -0
  36. data/dispatches/config.ru +7 -0
  37. data/dispatches/dispatch.fcgi +24 -0
  38. data/dispatches/dispatch.rb +10 -0
  39. data/dispatches/gateway.cgi +97 -0
  40. data/doc/README_FOR_APP +2 -0
  41. data/environments/boot.rb +110 -0
  42. data/environments/development.rb +17 -0
  43. data/environments/environment.rb +41 -0
  44. data/environments/production.rb +28 -0
  45. data/environments/test.rb +28 -0
  46. data/fresh_rakefile +10 -0
  47. data/guides/files/javascripts/code_highlighter.js +188 -0
  48. data/guides/files/javascripts/guides.js +8 -0
  49. data/guides/files/javascripts/highlighters.js +90 -0
  50. data/guides/files/stylesheets/main.css +441 -0
  51. data/guides/files/stylesheets/print.css +52 -0
  52. data/guides/files/stylesheets/reset.css +43 -0
  53. data/guides/files/stylesheets/style.css +13 -0
  54. data/guides/files/stylesheets/syntax.css +31 -0
  55. data/guides/images/belongs_to.png +0 -0
  56. data/guides/images/book_icon.gif +0 -0
  57. data/guides/images/bullet.gif +0 -0
  58. data/guides/images/chapters_icon.gif +0 -0
  59. data/guides/images/check_bullet.gif +0 -0
  60. data/guides/images/credits_pic_blank.gif +0 -0
  61. data/guides/images/csrf.png +0 -0
  62. data/guides/images/customized_error_messages.png +0 -0
  63. data/guides/images/error_messages.png +0 -0
  64. data/guides/images/feature_tile.gif +0 -0
  65. data/guides/images/footer_tile.gif +0 -0
  66. data/guides/images/fxn.jpg +0 -0
  67. data/guides/images/grey_bullet.gif +0 -0
  68. data/guides/images/habtm.png +0 -0
  69. data/guides/images/has_many.png +0 -0
  70. data/guides/images/has_many_through.png +0 -0
  71. data/guides/images/has_one.png +0 -0
  72. data/guides/images/has_one_through.png +0 -0
  73. data/guides/images/header_backdrop.png +0 -0
  74. data/guides/images/header_tile.gif +0 -0
  75. data/guides/images/i18n/demo_localized_pirate.png +0 -0
  76. data/guides/images/i18n/demo_translated_en.png +0 -0
  77. data/guides/images/i18n/demo_translated_pirate.png +0 -0
  78. data/guides/images/i18n/demo_translation_missing.png +0 -0
  79. data/guides/images/i18n/demo_untranslated.png +0 -0
  80. data/guides/images/icons/README +5 -0
  81. data/guides/images/icons/callouts/1.png +0 -0
  82. data/guides/images/icons/callouts/10.png +0 -0
  83. data/guides/images/icons/callouts/11.png +0 -0
  84. data/guides/images/icons/callouts/12.png +0 -0
  85. data/guides/images/icons/callouts/13.png +0 -0
  86. data/guides/images/icons/callouts/14.png +0 -0
  87. data/guides/images/icons/callouts/15.png +0 -0
  88. data/guides/images/icons/callouts/2.png +0 -0
  89. data/guides/images/icons/callouts/3.png +0 -0
  90. data/guides/images/icons/callouts/4.png +0 -0
  91. data/guides/images/icons/callouts/5.png +0 -0
  92. data/guides/images/icons/callouts/6.png +0 -0
  93. data/guides/images/icons/callouts/7.png +0 -0
  94. data/guides/images/icons/callouts/8.png +0 -0
  95. data/guides/images/icons/callouts/9.png +0 -0
  96. data/guides/images/icons/caution.png +0 -0
  97. data/guides/images/icons/example.png +0 -0
  98. data/guides/images/icons/home.png +0 -0
  99. data/guides/images/icons/important.png +0 -0
  100. data/guides/images/icons/next.png +0 -0
  101. data/guides/images/icons/note.png +0 -0
  102. data/guides/images/icons/prev.png +0 -0
  103. data/guides/images/icons/tip.png +0 -0
  104. data/guides/images/icons/up.png +0 -0
  105. data/guides/images/icons/warning.png +0 -0
  106. data/guides/images/nav_arrow.gif +0 -0
  107. data/guides/images/polymorphic.png +0 -0
  108. data/guides/images/posts_index.png +0 -0
  109. data/guides/images/rails_guides_logo.gif +0 -0
  110. data/guides/images/rails_logo_remix.gif +0 -0
  111. data/guides/images/rails_welcome.png +0 -0
  112. data/guides/images/session_fixation.png +0 -0
  113. data/guides/images/tab_grey.gif +0 -0
  114. data/guides/images/tab_info.gif +0 -0
  115. data/guides/images/tab_note.gif +0 -0
  116. data/guides/images/tab_red.gif +0 -0
  117. data/guides/images/tab_yellow.gif +0 -0
  118. data/guides/images/tab_yellow.png +0 -0
  119. data/guides/images/validation_error_messages.png +0 -0
  120. data/guides/rails_guides.rb +42 -0
  121. data/guides/rails_guides/generator.rb +138 -0
  122. data/guides/rails_guides/helpers.rb +34 -0
  123. data/guides/rails_guides/indexer.rb +55 -0
  124. data/guides/rails_guides/textile_extensions.rb +41 -0
  125. data/guides/source/2_2_release_notes.textile +422 -0
  126. data/guides/source/2_3_release_notes.textile +610 -0
  127. data/guides/source/action_controller_overview.textile +776 -0
  128. data/guides/source/action_mailer_basics.textile +424 -0
  129. data/guides/source/active_record_basics.textile +135 -0
  130. data/guides/source/active_record_querying.textile +969 -0
  131. data/guides/source/activerecord_validations_callbacks.textile +1086 -0
  132. data/guides/source/association_basics.textile +1781 -0
  133. data/guides/source/caching_with_rails.textile +524 -0
  134. data/guides/source/command_line.textile +589 -0
  135. data/guides/source/configuring.textile +234 -0
  136. data/guides/source/contribute.textile +71 -0
  137. data/guides/source/contributing_to_rails.textile +239 -0
  138. data/guides/source/credits.erb.textile +52 -0
  139. data/guides/source/debugging_rails_applications.textile +709 -0
  140. data/guides/source/form_helpers.textile +766 -0
  141. data/guides/source/getting_started.textile +1297 -0
  142. data/guides/source/i18n.textile +912 -0
  143. data/guides/source/index.erb.textile +124 -0
  144. data/guides/source/layout.html.erb +103 -0
  145. data/guides/source/layouts_and_rendering.textile +979 -0
  146. data/guides/source/migrations.textile +591 -0
  147. data/guides/source/nested_model_forms.textile +222 -0
  148. data/guides/source/performance_testing.textile +531 -0
  149. data/guides/source/plugins.textile +1512 -0
  150. data/guides/source/rails_on_rack.textile +309 -0
  151. data/guides/source/routing.textile +903 -0
  152. data/guides/source/security.textile +986 -0
  153. data/guides/source/testing.textile +951 -0
  154. data/helpers/application_controller.rb +10 -0
  155. data/helpers/application_helper.rb +3 -0
  156. data/helpers/performance_test.rb +9 -0
  157. data/helpers/test_helper.rb +38 -0
  158. data/html/404.html +30 -0
  159. data/html/422.html +30 -0
  160. data/html/500.html +30 -0
  161. data/html/favicon.ico +0 -0
  162. data/html/images/rails.png +0 -0
  163. data/html/index.html +275 -0
  164. data/html/javascripts/application.js +2 -0
  165. data/html/javascripts/controls.js +963 -0
  166. data/html/javascripts/dragdrop.js +973 -0
  167. data/html/javascripts/effects.js +1128 -0
  168. data/html/javascripts/prototype.js +4320 -0
  169. data/html/robots.txt +5 -0
  170. data/lib/code_statistics.rb +107 -0
  171. data/lib/commands.rb +17 -0
  172. data/lib/commands/about.rb +3 -0
  173. data/lib/commands/console.rb +45 -0
  174. data/lib/commands/dbconsole.rb +87 -0
  175. data/lib/commands/destroy.rb +6 -0
  176. data/lib/commands/generate.rb +6 -0
  177. data/lib/commands/ncgi/listener +86 -0
  178. data/lib/commands/ncgi/tracker +69 -0
  179. data/lib/commands/performance/benchmarker.rb +24 -0
  180. data/lib/commands/performance/profiler.rb +50 -0
  181. data/lib/commands/plugin.rb +968 -0
  182. data/lib/commands/runner.rb +54 -0
  183. data/lib/commands/server.rb +114 -0
  184. data/lib/commands/update.rb +4 -0
  185. data/lib/console_app.rb +30 -0
  186. data/lib/console_sandbox.rb +6 -0
  187. data/lib/console_with_helpers.rb +5 -0
  188. data/lib/dispatcher.rb +24 -0
  189. data/lib/fcgi_handler.rb +239 -0
  190. data/lib/initializer.rb +1128 -0
  191. data/lib/performance_test_help.rb +5 -0
  192. data/lib/rails/backtrace_cleaner.rb +54 -0
  193. data/lib/rails/gem_builder.rb +21 -0
  194. data/lib/rails/gem_dependency.rb +311 -0
  195. data/lib/rails/plugin.rb +179 -0
  196. data/lib/rails/plugin/loader.rb +198 -0
  197. data/lib/rails/plugin/locator.rb +100 -0
  198. data/lib/rails/rack.rb +8 -0
  199. data/lib/rails/rack/debugger.rb +23 -0
  200. data/lib/rails/rack/log_tailer.rb +35 -0
  201. data/lib/rails/rack/metal.rb +51 -0
  202. data/lib/rails/rack/static.rb +46 -0
  203. data/lib/rails/vendor_gem_source_index.rb +140 -0
  204. data/lib/rails/version.rb +9 -0
  205. data/lib/rails_generator.rb +43 -0
  206. data/lib/rails_generator/base.rb +266 -0
  207. data/lib/rails_generator/commands.rb +621 -0
  208. data/lib/rails_generator/generated_attribute.rb +46 -0
  209. data/lib/rails_generator/generators/applications/app/USAGE +9 -0
  210. data/lib/rails_generator/generators/applications/app/app_generator.rb +263 -0
  211. data/lib/rails_generator/generators/applications/app/scm/git.rb +18 -0
  212. data/lib/rails_generator/generators/applications/app/scm/scm.rb +8 -0
  213. data/lib/rails_generator/generators/applications/app/scm/svn.rb +7 -0
  214. data/lib/rails_generator/generators/applications/app/template_runner.rb +401 -0
  215. data/lib/rails_generator/generators/components/controller/USAGE +30 -0
  216. data/lib/rails_generator/generators/components/controller/controller_generator.rb +43 -0
  217. data/lib/rails_generator/generators/components/controller/templates/controller.rb +7 -0
  218. data/lib/rails_generator/generators/components/controller/templates/functional_test.rb +8 -0
  219. data/lib/rails_generator/generators/components/controller/templates/helper.rb +2 -0
  220. data/lib/rails_generator/generators/components/controller/templates/helper_test.rb +4 -0
  221. data/lib/rails_generator/generators/components/controller/templates/view.html.erb +2 -0
  222. data/lib/rails_generator/generators/components/helper/USAGE +24 -0
  223. data/lib/rails_generator/generators/components/helper/helper_generator.rb +25 -0
  224. data/lib/rails_generator/generators/components/helper/templates/helper.rb +2 -0
  225. data/lib/rails_generator/generators/components/helper/templates/helper_test.rb +4 -0
  226. data/lib/rails_generator/generators/components/integration_test/USAGE +8 -0
  227. data/lib/rails_generator/generators/components/integration_test/integration_test_generator.rb +16 -0
  228. data/lib/rails_generator/generators/components/integration_test/templates/integration_test.rb +10 -0
  229. data/lib/rails_generator/generators/components/mailer/USAGE +16 -0
  230. data/lib/rails_generator/generators/components/mailer/mailer_generator.rb +30 -0
  231. data/lib/rails_generator/generators/components/mailer/templates/fixture.erb +3 -0
  232. data/lib/rails_generator/generators/components/mailer/templates/fixture.rhtml +0 -0
  233. data/lib/rails_generator/generators/components/mailer/templates/mailer.rb +15 -0
  234. data/lib/rails_generator/generators/components/mailer/templates/unit_test.rb +20 -0
  235. data/lib/rails_generator/generators/components/mailer/templates/view.erb +3 -0
  236. data/lib/rails_generator/generators/components/mailer/templates/view.rhtml +0 -0
  237. data/lib/rails_generator/generators/components/metal/USAGE +8 -0
  238. data/lib/rails_generator/generators/components/metal/metal_generator.rb +8 -0
  239. data/lib/rails_generator/generators/components/metal/templates/metal.rb +12 -0
  240. data/lib/rails_generator/generators/components/migration/USAGE +29 -0
  241. data/lib/rails_generator/generators/components/migration/migration_generator.rb +20 -0
  242. data/lib/rails_generator/generators/components/migration/templates/migration.rb +11 -0
  243. data/lib/rails_generator/generators/components/model/USAGE +27 -0
  244. data/lib/rails_generator/generators/components/model/model_generator.rb +52 -0
  245. data/lib/rails_generator/generators/components/model/templates/fixtures.yml +19 -0
  246. data/lib/rails_generator/generators/components/model/templates/migration.rb +16 -0
  247. data/lib/rails_generator/generators/components/model/templates/model.rb +5 -0
  248. data/lib/rails_generator/generators/components/model/templates/unit_test.rb +8 -0
  249. data/lib/rails_generator/generators/components/observer/USAGE +13 -0
  250. data/lib/rails_generator/generators/components/observer/observer_generator.rb +16 -0
  251. data/lib/rails_generator/generators/components/observer/templates/observer.rb +2 -0
  252. data/lib/rails_generator/generators/components/observer/templates/unit_test.rb +8 -0
  253. data/lib/rails_generator/generators/components/performance_test/USAGE +8 -0
  254. data/lib/rails_generator/generators/components/performance_test/performance_test_generator.rb +16 -0
  255. data/lib/rails_generator/generators/components/performance_test/templates/performance_test.rb +9 -0
  256. data/lib/rails_generator/generators/components/plugin/USAGE +25 -0
  257. data/lib/rails_generator/generators/components/plugin/plugin_generator.rb +39 -0
  258. data/lib/rails_generator/generators/components/plugin/templates/MIT-LICENSE +20 -0
  259. data/lib/rails_generator/generators/components/plugin/templates/README +13 -0
  260. data/lib/rails_generator/generators/components/plugin/templates/Rakefile +23 -0
  261. data/lib/rails_generator/generators/components/plugin/templates/USAGE +8 -0
  262. data/lib/rails_generator/generators/components/plugin/templates/generator.rb +8 -0
  263. data/lib/rails_generator/generators/components/plugin/templates/init.rb +1 -0
  264. data/lib/rails_generator/generators/components/plugin/templates/install.rb +1 -0
  265. data/lib/rails_generator/generators/components/plugin/templates/plugin.rb +1 -0
  266. data/lib/rails_generator/generators/components/plugin/templates/tasks.rake +4 -0
  267. data/lib/rails_generator/generators/components/plugin/templates/test_helper.rb +3 -0
  268. data/lib/rails_generator/generators/components/plugin/templates/uninstall.rb +1 -0
  269. data/lib/rails_generator/generators/components/plugin/templates/unit_test.rb +8 -0
  270. data/lib/rails_generator/generators/components/resource/USAGE +23 -0
  271. data/lib/rails_generator/generators/components/resource/resource_generator.rb +76 -0
  272. data/lib/rails_generator/generators/components/resource/templates/controller.rb +2 -0
  273. data/lib/rails_generator/generators/components/resource/templates/functional_test.rb +8 -0
  274. data/lib/rails_generator/generators/components/resource/templates/helper.rb +2 -0
  275. data/lib/rails_generator/generators/components/resource/templates/helper_test.rb +4 -0
  276. data/lib/rails_generator/generators/components/scaffold/USAGE +29 -0
  277. data/lib/rails_generator/generators/components/scaffold/scaffold_generator.rb +103 -0
  278. data/lib/rails_generator/generators/components/scaffold/templates/controller.rb +85 -0
  279. data/lib/rails_generator/generators/components/scaffold/templates/functional_test.rb +45 -0
  280. data/lib/rails_generator/generators/components/scaffold/templates/helper.rb +2 -0
  281. data/lib/rails_generator/generators/components/scaffold/templates/helper_test.rb +4 -0
  282. data/lib/rails_generator/generators/components/scaffold/templates/layout.html.erb +17 -0
  283. data/lib/rails_generator/generators/components/scaffold/templates/style.css +54 -0
  284. data/lib/rails_generator/generators/components/scaffold/templates/view_edit.html.erb +18 -0
  285. data/lib/rails_generator/generators/components/scaffold/templates/view_index.html.erb +24 -0
  286. data/lib/rails_generator/generators/components/scaffold/templates/view_new.html.erb +17 -0
  287. data/lib/rails_generator/generators/components/scaffold/templates/view_show.html.erb +10 -0
  288. data/lib/rails_generator/generators/components/session_migration/USAGE +10 -0
  289. data/lib/rails_generator/generators/components/session_migration/session_migration_generator.rb +18 -0
  290. data/lib/rails_generator/generators/components/session_migration/templates/migration.rb +16 -0
  291. data/lib/rails_generator/lookup.rb +249 -0
  292. data/lib/rails_generator/manifest.rb +53 -0
  293. data/lib/rails_generator/options.rb +150 -0
  294. data/lib/rails_generator/scripts.rb +89 -0
  295. data/lib/rails_generator/scripts/destroy.rb +29 -0
  296. data/lib/rails_generator/scripts/generate.rb +7 -0
  297. data/lib/rails_generator/scripts/update.rb +12 -0
  298. data/lib/rails_generator/secret_key_generator.rb +24 -0
  299. data/lib/rails_generator/simple_logger.rb +46 -0
  300. data/lib/rails_generator/spec.rb +44 -0
  301. data/lib/railties_path.rb +1 -0
  302. data/lib/ruby_version_check.rb +17 -0
  303. data/lib/rubyprof_ext.rb +35 -0
  304. data/lib/source_annotation_extractor.rb +102 -0
  305. data/lib/tasks/annotations.rake +20 -0
  306. data/lib/tasks/databases.rake +436 -0
  307. data/lib/tasks/documentation.rake +88 -0
  308. data/lib/tasks/framework.rake +143 -0
  309. data/lib/tasks/gems.rake +78 -0
  310. data/lib/tasks/log.rake +9 -0
  311. data/lib/tasks/middleware.rake +7 -0
  312. data/lib/tasks/misc.rake +63 -0
  313. data/lib/tasks/rails.rb +9 -0
  314. data/lib/tasks/routes.rake +18 -0
  315. data/lib/tasks/statistics.rake +17 -0
  316. data/lib/tasks/testing.rake +139 -0
  317. data/lib/tasks/tmp.rake +37 -0
  318. data/lib/test_help.rb +38 -0
  319. data/lib/webrick_server.rb +156 -0
  320. metadata +495 -0
@@ -0,0 +1,524 @@
1
+ h2. Caching with Rails: An overview
2
+
3
+ Everyone caches. This guide will teach you what you need to know about
4
+ avoiding that expensive round-trip to your database and returning what you
5
+ need to return to those hungry web clients in the shortest time possible.
6
+
7
+ After reading this guide, you should be able to use and configure:
8
+
9
+ * Page, action, and fragment caching
10
+ * Sweepers
11
+ * Alternative cache stores
12
+ * Conditional GET support
13
+
14
+ endprologue.
15
+
16
+ h3. Basic Caching
17
+
18
+ This is an introduction to the three types of caching techniques that Rails
19
+ provides by default without the use of any third party plugins.
20
+
21
+ To get started make sure +config.action_controller.perform_caching+ is set
22
+ to +true+ for your environment. This flag is normally set in the
23
+ corresponding config/environments/*.rb. By default, caching is disabled for development and test, and enabled for production.
24
+
25
+ <ruby>
26
+ config.action_controller.perform_caching = true
27
+ </ruby>
28
+
29
+ h4. Page Caching
30
+
31
+ Page caching is a Rails mechanism which allows the request for a generated
32
+ page to be fulfilled by the webserver, without ever having to go through the
33
+ Rails stack at all. Obviously, this is super-fast. Unfortunately, it can't be
34
+ applied to every situation (such as pages that need authentication) and since
35
+ the webserver is literally just serving a file from the filesystem, cache
36
+ expiration is an issue that needs to be dealt with.
37
+
38
+ So, how do you enable this super-fast cache behavior? Suppose you
39
+ have a controller called +ProductsController+ and an +index+ action that lists all
40
+ the products. You could enable caching for this action like this:
41
+
42
+ <ruby>
43
+ class ProductsController < ActionController
44
+
45
+ caches_page :index
46
+
47
+ def index; end
48
+
49
+ end
50
+ </ruby>
51
+
52
+ The first time anyone requests products/index, Rails will generate a file
53
+ called +index.html+. If a web server see this file, it will be served in response to the
54
+ next request for products/index, without your Rails application being called.
55
+
56
+ By default, the page cache directory is set to Rails.public_path (which is
57
+ usually set to +File.join(self.root, "public")+ - that is, the public directory under your Rails application's root). This can be configured by
58
+ changing the configuration setting +config.action_controller.page_cache_directory+.
59
+ Changing the default from /public helps avoid naming conflicts, since you may
60
+ want to put other static html in /public, but changing this will require web
61
+ server reconfiguration to let the web server know where to serve the cached
62
+ files from.
63
+
64
+ The page caching mechanism will automatically add a +.html+ extension to
65
+ requests for pages that do not have an extension to make it easy for the
66
+ webserver to find those pages. This can be configured by changing the
67
+ configuration setting +config.action_controller.page_cache_extension+.
68
+
69
+ In order to expire this page when a new product is added you could extend the products controller like this:
70
+
71
+ <ruby>
72
+ class ProductsController < ActionController
73
+
74
+ caches_page :index
75
+
76
+ def index; end
77
+
78
+ def create
79
+ expire_page :action => :index
80
+ end
81
+
82
+ end
83
+ </ruby>
84
+
85
+ If you want a more complicated expiration scheme, you can use cache sweepers
86
+ to expire cached objects when things change. This is covered in the section on Sweepers.
87
+
88
+ Note: Page caching ignores all parameters, so /products/list?page=1 will be written out to the filesystem as /products/list.html and if someone requests /products/list?page=2, they will be returned the same result as page=1. Be careful when page caching GET parameters in the URL!
89
+
90
+ h4. Action Caching
91
+
92
+ One of the issues with page caching is that you cannot use it for pages that
93
+ require checking code to determine whether the user should be permitted access. This is where Action Caching comes in.
94
+ action caching works like page caching except for the fact that the incoming
95
+ web request does go from the web server to the Rails stack and Action Pack so
96
+ that before filters can be run on it before the cache is served. This allows you to use
97
+ authentication and other restrictions while still serving the
98
+ result of the output from a cached copy.
99
+
100
+ Clearing the cache works in the exact same way as with page caching.
101
+
102
+ Let's say you only wanted authenticated users to edit or create a Product
103
+ object, but still cache those pages:
104
+
105
+ <ruby>
106
+ class ProductsController < ActionController
107
+
108
+ before_filter :authenticate, :only => [ :edit, :create ]
109
+ caches_page :index
110
+ caches_action :edit
111
+
112
+ def index; end
113
+
114
+ def create
115
+ expire_page :action => :index
116
+ expire_action :action => :edit
117
+ end
118
+
119
+ def edit; end
120
+
121
+ end
122
+ </ruby>
123
+
124
+ You can also use +:if+ (or +:unless+) to pass a Proc that specifies when the
125
+ action should be cached. Also, you can use +:layout => false+ to cache without
126
+ layout so that dynamic information in the layout such as the name of the logged-in user
127
+ or the number of items in the cart can be left uncached. This feature is
128
+ available as of Rails 2.2.
129
+
130
+ You can modify the default action cache path by passing a +:cache_path+ option.
131
+ This will be passed directly to +ActionCachePath.path_for+. This is handy for
132
+ actions with multiple possible routes that should be cached differently. If
133
+ a block is given, it is called with the current controller instance.
134
+
135
+ Finally, if you are using memcached, you can also pass +:expires_in+. In fact,
136
+ all parameters not used by +caches_action+ are sent to the underlying cache
137
+ store.
138
+
139
+ h4. Fragment Caching
140
+
141
+ Life would be perfect if we could get away with caching the entire contents of
142
+ a page or action and serving it out to the world. Unfortunately, dynamic web
143
+ applications usually build pages with a variety of components not all of which
144
+ have the same caching characteristics. In order to address such a dynamically
145
+ created page where different parts of the page need to be cached and expired
146
+ differently Rails provides a mechanism called Fragment Caching.
147
+
148
+ Fragment Caching allows a fragment of view logic to be wrapped in a cache
149
+ block and served out of the cache store when the next request comes in.
150
+
151
+ As an example, if you wanted to show all the orders placed on your website
152
+ in real time and didn't want to cache that part of the page, but did want
153
+ to cache the part of the page which lists all products available, you
154
+ could use this piece of code:
155
+
156
+ <ruby>
157
+ <% Order.find_recent.each do |o| %>
158
+ <%= o.buyer.name %> bought <% o.product.name %>
159
+ <% end %>
160
+
161
+ <% cache do %>
162
+ All available products:
163
+ <% Product.find(:all).each do |p| %>
164
+ <%= link_to p.name, product_url(p) %>
165
+ <% end %>
166
+ <% end %>
167
+ </ruby>
168
+
169
+ The cache block in our example will bind to the action that called it and is
170
+ written out to the same place as the action cache, which means that if you
171
+ want to cache multiple fragments per action, you should provide an +action_suffix+ to the cache call:
172
+
173
+ <ruby>
174
+ <% cache(:action => 'recent', :action_suffix => 'all_prods') do %>
175
+ All available products:
176
+ </ruby>
177
+
178
+ You can expire the cache using the +expire_fragment+ method, like so:
179
+
180
+ <ruby>
181
+ expire_fragment(:controller => 'products', :action => 'recent',
182
+ :action_suffix => 'all_prods)
183
+ </ruby>
184
+
185
+ If you don't want the cache block to bind to the action that called it, you can
186
+ also use globally keyed fragments. To do this, call the +cache+ method with a key, like
187
+ so:
188
+
189
+ <ruby>
190
+ <% cache(:key =>
191
+ ['all_available_products', @latest_product.created_at].join(':')) do %>
192
+ All available products:
193
+ <% end %>
194
+ </ruby>
195
+
196
+ This fragment is then available to all actions in the +ProductsController+ using
197
+ the key and can be expired the same way:
198
+
199
+ <ruby>
200
+ expire_fragment(:key =>
201
+ ['all_available_products', @latest_product.created_at].join(':'))
202
+ </ruby>
203
+
204
+ h4. Sweepers
205
+
206
+ Cache sweeping is a mechanism which allows you to get around having a ton of
207
+ +expire_{page,action,fragment}+ calls in your code. It does this by moving all the work
208
+ required to expire cached content into na +ActionController::Caching::Sweeper+
209
+ class. This class is an Observer that looks for changes to an object via callbacks,
210
+ and when a change occurs it expires the caches associated with that object in
211
+ an around or after filter.
212
+
213
+ Continuing with our Product controller example, we could rewrite it with a
214
+ sweeper like this:
215
+
216
+ <ruby>
217
+ class StoreSweeper < ActionController::Caching::Sweeper
218
+ # This sweeper is going to keep an eye on the Product model
219
+ observe Product
220
+
221
+ # If our sweeper detects that a Product was created call this
222
+ def after_create(product)
223
+ expire_cache_for(product)
224
+ end
225
+
226
+ # If our sweeper detects that a Product was updated call this
227
+ def after_update(product)
228
+ expire_cache_for(product)
229
+ end
230
+
231
+ # If our sweeper detects that a Product was deleted call this
232
+ def after_destroy(product)
233
+ expire_cache_for(product)
234
+ end
235
+
236
+ private
237
+ def expire_cache_for(record)
238
+ # Expire the list page now that we added a new product
239
+ expire_page(:controller => '#{record}', :action => 'list')
240
+
241
+ # Expire a fragment
242
+ expire_fragment(:controller => '#{record}',
243
+ :action => 'recent', :action_suffix => 'all_products')
244
+ end
245
+ end
246
+ </ruby>
247
+
248
+ The sweeper has to be added to the controller that will use it. So, if we wanted to expire the cached content for the
249
+ list and edit actions when the create action was called, we could do the
250
+ following:
251
+
252
+ <ruby>
253
+ class ProductsController < ActionController
254
+
255
+ before_filter :authenticate, :only => [ :edit, :create ]
256
+ caches_page :list
257
+ caches_action :edit
258
+ cache_sweeper :store_sweeper, :only => [ :create ]
259
+
260
+ def list; end
261
+
262
+ def create
263
+ expire_page :action => :list
264
+ expire_action :action => :edit
265
+ end
266
+
267
+ def edit; end
268
+
269
+ end
270
+ </ruby>
271
+
272
+ h4. SQL Caching
273
+
274
+ Query caching is a Rails feature that caches the result set returned by each
275
+ query. If Rails encounters the same query again during the current request, it
276
+ will used the cached result set as opposed to running the query against the
277
+ database.
278
+
279
+ For example:
280
+
281
+ <ruby>
282
+ class ProductsController < ActionController
283
+
284
+ before_filter :authenticate, :only => [ :edit, :create ]
285
+ caches_page :list
286
+ caches_action :edit
287
+ cache_sweeper :store_sweeper, :only => [ :create ]
288
+
289
+ def list
290
+ # Run a find query
291
+ Product.find(:all)
292
+
293
+ ...
294
+
295
+ # Run the same query again
296
+ Product.find(:all)
297
+ end
298
+
299
+ def create
300
+ expire_page :action => :list
301
+ expire_action :action => :edit
302
+ end
303
+
304
+ def edit; end
305
+
306
+ end
307
+ </ruby>
308
+
309
+ In the 'list' action above, the result set returned by the first
310
+ Product.find(:all) will be cached and will be used to avoid querying the
311
+ database again the second time that finder is called.
312
+
313
+ Query caches are created at the start of an action and destroyed at the end of
314
+ that action and thus persist only for the duration of the action.
315
+
316
+ h4. Cache Stores
317
+
318
+ Rails (as of 2.1) provides different stores for the cached data created by action and
319
+ fragment caches. Page caches are always stored on disk.
320
+
321
+ Rails 2.1 and above provide ActiveSupport::Cache::Store which can be used to
322
+ cache strings. Some cache store implementations, like MemoryStore, are able to
323
+ cache arbitrary Ruby objects, but don't count on every cache store to be able
324
+ to do that.
325
+
326
+ The default cache stores provided with Rails include:
327
+
328
+ 1) ActiveSupport::Cache::MemoryStore: A cache store implementation which stores
329
+ everything into memory in the same process. If you're running multiple Ruby on
330
+ Rails server processes (which is the case if you're using mongrel_cluster or
331
+ Phusion Passenger), then this means that your Rails server process instances
332
+ won't be able to share cache data with each other. If your application never
333
+ performs manual cache item expiry (e.g. when you‘re using generational cache
334
+ keys), then using +MemoryStore+ is ok. Otherwise, consider carefully whether you
335
+ should be using this cache store.
336
+
337
+ +MemoryStore+ is not only able to store strings, but also arbitrary Ruby objects.
338
+
339
+ +MemoryStore+ is not thread-safe. Use +SynchronizedMemoryStore+ instead if you
340
+ need thread-safety.
341
+
342
+
343
+ <ruby>
344
+ ActionController::Base.cache_store = :memory_store
345
+ </ruby>
346
+
347
+ 2) ActiveSupport::Cache::FileStore: Cached data is stored on the disk. This is
348
+ the default store and the default path for this store is: /tmp/cache. Works
349
+ well for all types of environments and allows all processes running from the
350
+ same application directory to access the cached content. If /tmp/cache does not
351
+ exist, the default store becomes MemoryStore.
352
+
353
+ <ruby>
354
+ ActionController::Base.cache_store = :file_store, "/path/to/cache/directory"
355
+ </ruby>
356
+
357
+ 3) ActiveSupport::Cache::DRbStore: Cached data is stored in a separate shared
358
+ DRb process that all servers communicate with. This works for all environments
359
+ and only keeps one cache around for all processes, but requires that you run
360
+ and manage a separate DRb process.
361
+
362
+ <ruby>
363
+ ActionController::Base.cache_store = :drb_store, "druby://localhost:9192"
364
+ </ruby>
365
+
366
+ 4) MemCached store: Works like DRbStore, but uses Danga's MemCache instead.
367
+ Rails uses the bundled memcached-client gem by default. This is currently the
368
+ most popular cache store for production websites.
369
+
370
+ Special features:
371
+
372
+ * Clustering and load balancing. One can specify multiple memcached servers,
373
+ and MemCacheStore will load balance between all available servers. If a
374
+ server goes down, then MemCacheStore will ignore it until it goes back
375
+ online.
376
+ * Time-based expiry support. See +write+ and the +:expires_in+ option.
377
+ * Per-request in memory cache for all communication with the MemCache server(s).
378
+
379
+ It also accepts a hash of additional options:
380
+
381
+ * +:namespace+- specifies a string that will automatically be prepended to keys when accessing the memcached store.
382
+ * +:readonly+- a boolean value that when set to true will make the store read-only, with an error raised on any attempt to write.
383
+ * +:multithread+ - a boolean value that adds thread safety to read/write operations - it is unlikely you'll need to use this option as the Rails threadsafe! method offers the same functionality.
384
+
385
+ The read and write methods of the MemCacheStore accept an options hash too.
386
+ When reading you can specify +:raw => true+ to prevent the object being
387
+ marshaled
388
+ (by default this is false which means the raw value in the cache is passed to
389
+ +Marshal.load+ before being returned to you.)
390
+
391
+ When writing to the cache it is also possible to specify +:raw => true+. This means
392
+ that the value is not passed to +Marshal.dump+ before being stored in the cache (by
393
+ default this is false).
394
+
395
+ The write method also accepts an +:unless_exist+ flag which determines whether
396
+ the memcached add (when true) or set (when false) method is used to store the
397
+ item in the cache and an +:expires_in+ option that specifies the time-to-live
398
+ for the cached item in seconds.
399
+
400
+
401
+ <ruby>
402
+ ActionController::Base.cache_store = :mem_cache_store, "localhost"
403
+ </ruby>
404
+
405
+ 5) ActiveSupport::Cache::SynchronizedMemoryStore: Like ActiveSupport::Cache::MemoryStore but thread-safe.
406
+
407
+
408
+ <ruby>
409
+ ActionController::Base.cache_store = :synchronized_memory_store
410
+ </ruby>
411
+
412
+ 6) ActiveSupport::Cache::CompressedMemCacheStore: Works just like the regular
413
+ MemCacheStore but uses GZip to decompress/compress on read/write.
414
+
415
+
416
+ <ruby>
417
+ ActionController::Base.cache_store = :compressed_mem_cache_store, "localhost"
418
+ </ruby>
419
+
420
+ 7) Custom store: You can define your own cache store (new in Rails 2.1)
421
+
422
+
423
+ <ruby>
424
+ ActionController::Base.cache_store = MyOwnStore.new("parameter")
425
+ </ruby>
426
+
427
+ NOTE: +config.cache_store+ can be used in place of
428
+ +ActionController::Base.cache_store+ in the +Rails::Initializer.run+ block in
429
+ environment.rb.
430
+
431
+ In addition to all of this, Rails also adds the +ActiveRecord::Base#cache_key+
432
+ method that generates a key using the class name, id and updated_at timestamp
433
+ (if available).
434
+
435
+ An example:
436
+
437
+ <ruby>
438
+ Rails.cache.read("city") # => nil
439
+ Rails.cache.write("city", "Duckburgh")
440
+ Rails.cache.read("city") # => "Duckburgh"
441
+ </ruby>
442
+
443
+ h3. Conditional GET Support
444
+
445
+ Conditional GETs are a feature of the HTTP specification that provide a way for web
446
+ servers to tell browsers that the response to a GET request hasn't changed
447
+ since the last request and can be safely pulled from the browser cache.
448
+
449
+ They work by using the HTTP_IF_NONE_MATCH and HTTP_IF_MODIFIED_SINCE headers to
450
+ pass back and forth both a unique content identifier and the timestamp of when
451
+ the content was last changed. If the browser makes a request where the content
452
+ identifier (etag) or last modified since timestamp matches the server’s version
453
+ then the server only needs to send back an empty response with a not modified
454
+ status.
455
+
456
+ It is the server's (i.e. our) responsibility to look for a last modified
457
+ timestamp and the if-none-match header and determine whether or not to send
458
+ back the full response. With conditional-get support in rails this is a pretty
459
+ easy task:
460
+
461
+ <ruby>
462
+ class ProductsController < ApplicationController
463
+
464
+ def show
465
+ @product = Product.find(params[:id])
466
+
467
+ # If the request is stale according to the given timestamp and etag value
468
+ # (i.e. it needs to be processed again) then execute this block
469
+ if stale?(:last_modified => @product.updated_at.utc, :etag => @product)
470
+ respond_to do |wants|
471
+ # ... normal response processing
472
+ end
473
+ end
474
+
475
+ # If the request is fresh (i.e. it's not modified) then you don't need to do
476
+ # anything. The default render checks for this using the parameters
477
+ # used in the previous call to stale? and will automatically send a
478
+ # :not_modified. So that's it, you're done.
479
+ end
480
+ </ruby>
481
+
482
+ If you don't have any special response processing and are using the default
483
+ rendering mechanism (i.e. you're not using respond_to or calling render
484
+ yourself) then you’ve got an easy helper in fresh_when:
485
+
486
+ <ruby>
487
+ class ProductsController < ApplicationController
488
+
489
+ # This will automatically send back a :not_modified if the request is fresh,
490
+ # and will render the default template (product.*) if it's stale.
491
+
492
+ def show
493
+ @product = Product.find(params[:id])
494
+ fresh_when :last_modified => @product.published_at.utc, :etag => @article
495
+ end
496
+ end
497
+ </ruby>
498
+
499
+ h3. Advanced Caching
500
+
501
+ Along with the built-in mechanisms outlined above, a number of excellent
502
+ plugins exist to help with finer grained control over caching. These include
503
+ Chris Wanstrath's excellent cache_fu plugin (more info "here": http://errtheblog.com/posts/57-kickin-ass-w-cachefu) and Evan Weaver's
504
+ interlock plugin (more info "here": http://blog.evanweaver.com/articles/2007/12/13/better-rails-caching/). Both
505
+ of these plugins play nice with memcached and are a must-see for anyone
506
+ seriously considering optimizing their caching needs.
507
+
508
+ Also the new "Cache money":http://github.com/nkallen/cache-money/tree/master plugin is supposed to be mad cool.
509
+
510
+ h3. References
511
+
512
+ * "RailsEnvy, Rails Caching Tutorial, Part 1":http://www.railsenvy.com/2007/2/28/rails-caching-tutorial
513
+ * "RailsEnvy, Rails Caching Tutorial, Part 1":http://www.railsenvy.com/2007/3/20/ruby-on-rails-caching-tutorial-part-2
514
+ * "ActiveSupport::Cache documentation":http://api.rubyonrails.org/classes/ActiveSupport/Cache.html
515
+ * "Rails 2.1 integrated caching tutorial":http://thewebfellas.com/blog/2008/6/9/rails-2-1-now-with-better-integrated-caching
516
+
517
+ h3. Changelog
518
+
519
+ "Lighthouse ticket":http://rails.lighthouseapp.com/projects/16213-rails-guides/tickets/10-guide-to-caching
520
+
521
+ * February 22, 2009: Beefed up the section on cache_stores
522
+ * December 27, 2008: Typo fixes
523
+ * November 23, 2008: Incremental updates with various suggested changes and formatting cleanup
524
+ * September 15, 2008: Initial version by Aditya Chadha