rails_csi 2.3.5.p6
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +2172 -0
- data/MIT-LICENSE +20 -0
- data/README +243 -0
- data/Rakefile +368 -0
- data/bin/about +4 -0
- data/bin/console +3 -0
- data/bin/dbconsole +3 -0
- data/bin/destroy +3 -0
- data/bin/generate +3 -0
- data/bin/performance/benchmarker +3 -0
- data/bin/performance/profiler +3 -0
- data/bin/plugin +3 -0
- data/bin/rails +20 -0
- data/bin/runner +3 -0
- data/bin/server +3 -0
- data/builtin/rails_info/rails/info.rb +131 -0
- data/builtin/rails_info/rails/info_controller.rb +9 -0
- data/builtin/rails_info/rails/info_helper.rb +2 -0
- data/builtin/rails_info/rails_info_controller.rb +2 -0
- data/configs/databases/frontbase.yml +28 -0
- data/configs/databases/ibm_db.yml +62 -0
- data/configs/databases/mysql.yml +60 -0
- data/configs/databases/oracle.yml +39 -0
- data/configs/databases/postgresql.yml +51 -0
- data/configs/databases/sqlite2.yml +19 -0
- data/configs/databases/sqlite3.yml +22 -0
- data/configs/empty.log +0 -0
- data/configs/initializers/backtrace_silencers.rb +7 -0
- data/configs/initializers/inflections.rb +10 -0
- data/configs/initializers/mime_types.rb +5 -0
- data/configs/initializers/new_rails_defaults.rb +21 -0
- data/configs/initializers/session_store.rb +15 -0
- data/configs/locales/en.yml +5 -0
- data/configs/routes.rb +43 -0
- data/configs/seeds.rb +7 -0
- data/dispatches/config.ru +7 -0
- data/dispatches/dispatch.fcgi +24 -0
- data/dispatches/dispatch.rb +10 -0
- data/dispatches/gateway.cgi +97 -0
- data/doc/README_FOR_APP +2 -0
- data/environments/boot.rb +110 -0
- data/environments/development.rb +17 -0
- data/environments/environment.rb +41 -0
- data/environments/production.rb +28 -0
- data/environments/test.rb +28 -0
- data/fresh_rakefile +10 -0
- data/guides/files/javascripts/code_highlighter.js +188 -0
- data/guides/files/javascripts/guides.js +8 -0
- data/guides/files/javascripts/highlighters.js +90 -0
- data/guides/files/stylesheets/main.css +441 -0
- data/guides/files/stylesheets/print.css +52 -0
- data/guides/files/stylesheets/reset.css +43 -0
- data/guides/files/stylesheets/style.css +13 -0
- data/guides/files/stylesheets/syntax.css +31 -0
- data/guides/images/belongs_to.png +0 -0
- data/guides/images/book_icon.gif +0 -0
- data/guides/images/bullet.gif +0 -0
- data/guides/images/chapters_icon.gif +0 -0
- data/guides/images/check_bullet.gif +0 -0
- data/guides/images/credits_pic_blank.gif +0 -0
- data/guides/images/csrf.png +0 -0
- data/guides/images/customized_error_messages.png +0 -0
- data/guides/images/error_messages.png +0 -0
- data/guides/images/feature_tile.gif +0 -0
- data/guides/images/footer_tile.gif +0 -0
- data/guides/images/fxn.jpg +0 -0
- data/guides/images/grey_bullet.gif +0 -0
- data/guides/images/habtm.png +0 -0
- data/guides/images/has_many.png +0 -0
- data/guides/images/has_many_through.png +0 -0
- data/guides/images/has_one.png +0 -0
- data/guides/images/has_one_through.png +0 -0
- data/guides/images/header_backdrop.png +0 -0
- data/guides/images/header_tile.gif +0 -0
- data/guides/images/i18n/demo_localized_pirate.png +0 -0
- data/guides/images/i18n/demo_translated_en.png +0 -0
- data/guides/images/i18n/demo_translated_pirate.png +0 -0
- data/guides/images/i18n/demo_translation_missing.png +0 -0
- data/guides/images/i18n/demo_untranslated.png +0 -0
- data/guides/images/icons/README +5 -0
- data/guides/images/icons/callouts/1.png +0 -0
- data/guides/images/icons/callouts/10.png +0 -0
- data/guides/images/icons/callouts/11.png +0 -0
- data/guides/images/icons/callouts/12.png +0 -0
- data/guides/images/icons/callouts/13.png +0 -0
- data/guides/images/icons/callouts/14.png +0 -0
- data/guides/images/icons/callouts/15.png +0 -0
- data/guides/images/icons/callouts/2.png +0 -0
- data/guides/images/icons/callouts/3.png +0 -0
- data/guides/images/icons/callouts/4.png +0 -0
- data/guides/images/icons/callouts/5.png +0 -0
- data/guides/images/icons/callouts/6.png +0 -0
- data/guides/images/icons/callouts/7.png +0 -0
- data/guides/images/icons/callouts/8.png +0 -0
- data/guides/images/icons/callouts/9.png +0 -0
- data/guides/images/icons/caution.png +0 -0
- data/guides/images/icons/example.png +0 -0
- data/guides/images/icons/home.png +0 -0
- data/guides/images/icons/important.png +0 -0
- data/guides/images/icons/next.png +0 -0
- data/guides/images/icons/note.png +0 -0
- data/guides/images/icons/prev.png +0 -0
- data/guides/images/icons/tip.png +0 -0
- data/guides/images/icons/up.png +0 -0
- data/guides/images/icons/warning.png +0 -0
- data/guides/images/nav_arrow.gif +0 -0
- data/guides/images/polymorphic.png +0 -0
- data/guides/images/posts_index.png +0 -0
- data/guides/images/rails_guides_logo.gif +0 -0
- data/guides/images/rails_logo_remix.gif +0 -0
- data/guides/images/rails_welcome.png +0 -0
- data/guides/images/session_fixation.png +0 -0
- data/guides/images/tab_grey.gif +0 -0
- data/guides/images/tab_info.gif +0 -0
- data/guides/images/tab_note.gif +0 -0
- data/guides/images/tab_red.gif +0 -0
- data/guides/images/tab_yellow.gif +0 -0
- data/guides/images/tab_yellow.png +0 -0
- data/guides/images/validation_error_messages.png +0 -0
- data/guides/rails_guides.rb +42 -0
- data/guides/rails_guides/generator.rb +138 -0
- data/guides/rails_guides/helpers.rb +34 -0
- data/guides/rails_guides/indexer.rb +55 -0
- data/guides/rails_guides/textile_extensions.rb +41 -0
- data/guides/source/2_2_release_notes.textile +422 -0
- data/guides/source/2_3_release_notes.textile +610 -0
- data/guides/source/action_controller_overview.textile +776 -0
- data/guides/source/action_mailer_basics.textile +424 -0
- data/guides/source/active_record_basics.textile +135 -0
- data/guides/source/active_record_querying.textile +969 -0
- data/guides/source/activerecord_validations_callbacks.textile +1086 -0
- data/guides/source/association_basics.textile +1781 -0
- data/guides/source/caching_with_rails.textile +524 -0
- data/guides/source/command_line.textile +589 -0
- data/guides/source/configuring.textile +234 -0
- data/guides/source/contribute.textile +71 -0
- data/guides/source/contributing_to_rails.textile +239 -0
- data/guides/source/credits.erb.textile +52 -0
- data/guides/source/debugging_rails_applications.textile +709 -0
- data/guides/source/form_helpers.textile +766 -0
- data/guides/source/getting_started.textile +1297 -0
- data/guides/source/i18n.textile +912 -0
- data/guides/source/index.erb.textile +124 -0
- data/guides/source/layout.html.erb +103 -0
- data/guides/source/layouts_and_rendering.textile +979 -0
- data/guides/source/migrations.textile +591 -0
- data/guides/source/nested_model_forms.textile +222 -0
- data/guides/source/performance_testing.textile +531 -0
- data/guides/source/plugins.textile +1512 -0
- data/guides/source/rails_on_rack.textile +309 -0
- data/guides/source/routing.textile +903 -0
- data/guides/source/security.textile +986 -0
- data/guides/source/testing.textile +951 -0
- data/helpers/application_controller.rb +10 -0
- data/helpers/application_helper.rb +3 -0
- data/helpers/performance_test.rb +9 -0
- data/helpers/test_helper.rb +38 -0
- data/html/404.html +30 -0
- data/html/422.html +30 -0
- data/html/500.html +30 -0
- data/html/favicon.ico +0 -0
- data/html/images/rails.png +0 -0
- data/html/index.html +275 -0
- data/html/javascripts/application.js +2 -0
- data/html/javascripts/controls.js +963 -0
- data/html/javascripts/dragdrop.js +973 -0
- data/html/javascripts/effects.js +1128 -0
- data/html/javascripts/prototype.js +4320 -0
- data/html/robots.txt +5 -0
- data/lib/code_statistics.rb +107 -0
- data/lib/commands.rb +17 -0
- data/lib/commands/about.rb +3 -0
- data/lib/commands/console.rb +45 -0
- data/lib/commands/dbconsole.rb +87 -0
- data/lib/commands/destroy.rb +6 -0
- data/lib/commands/generate.rb +6 -0
- data/lib/commands/ncgi/listener +86 -0
- data/lib/commands/ncgi/tracker +69 -0
- data/lib/commands/performance/benchmarker.rb +24 -0
- data/lib/commands/performance/profiler.rb +50 -0
- data/lib/commands/plugin.rb +968 -0
- data/lib/commands/runner.rb +54 -0
- data/lib/commands/server.rb +114 -0
- data/lib/commands/update.rb +4 -0
- data/lib/console_app.rb +30 -0
- data/lib/console_sandbox.rb +6 -0
- data/lib/console_with_helpers.rb +5 -0
- data/lib/dispatcher.rb +24 -0
- data/lib/fcgi_handler.rb +239 -0
- data/lib/initializer.rb +1128 -0
- data/lib/performance_test_help.rb +5 -0
- data/lib/rails/backtrace_cleaner.rb +54 -0
- data/lib/rails/gem_builder.rb +21 -0
- data/lib/rails/gem_dependency.rb +311 -0
- data/lib/rails/plugin.rb +179 -0
- data/lib/rails/plugin/loader.rb +198 -0
- data/lib/rails/plugin/locator.rb +100 -0
- data/lib/rails/rack.rb +8 -0
- data/lib/rails/rack/debugger.rb +23 -0
- data/lib/rails/rack/log_tailer.rb +35 -0
- data/lib/rails/rack/metal.rb +51 -0
- data/lib/rails/rack/static.rb +46 -0
- data/lib/rails/vendor_gem_source_index.rb +140 -0
- data/lib/rails/version.rb +9 -0
- data/lib/rails_generator.rb +43 -0
- data/lib/rails_generator/base.rb +266 -0
- data/lib/rails_generator/commands.rb +621 -0
- data/lib/rails_generator/generated_attribute.rb +46 -0
- data/lib/rails_generator/generators/applications/app/USAGE +9 -0
- data/lib/rails_generator/generators/applications/app/app_generator.rb +263 -0
- data/lib/rails_generator/generators/applications/app/scm/git.rb +18 -0
- data/lib/rails_generator/generators/applications/app/scm/scm.rb +8 -0
- data/lib/rails_generator/generators/applications/app/scm/svn.rb +7 -0
- data/lib/rails_generator/generators/applications/app/template_runner.rb +401 -0
- data/lib/rails_generator/generators/components/controller/USAGE +30 -0
- data/lib/rails_generator/generators/components/controller/controller_generator.rb +43 -0
- data/lib/rails_generator/generators/components/controller/templates/controller.rb +7 -0
- data/lib/rails_generator/generators/components/controller/templates/functional_test.rb +8 -0
- data/lib/rails_generator/generators/components/controller/templates/helper.rb +2 -0
- data/lib/rails_generator/generators/components/controller/templates/helper_test.rb +4 -0
- data/lib/rails_generator/generators/components/controller/templates/view.html.erb +2 -0
- data/lib/rails_generator/generators/components/helper/USAGE +24 -0
- data/lib/rails_generator/generators/components/helper/helper_generator.rb +25 -0
- data/lib/rails_generator/generators/components/helper/templates/helper.rb +2 -0
- data/lib/rails_generator/generators/components/helper/templates/helper_test.rb +4 -0
- data/lib/rails_generator/generators/components/integration_test/USAGE +8 -0
- data/lib/rails_generator/generators/components/integration_test/integration_test_generator.rb +16 -0
- data/lib/rails_generator/generators/components/integration_test/templates/integration_test.rb +10 -0
- data/lib/rails_generator/generators/components/mailer/USAGE +16 -0
- data/lib/rails_generator/generators/components/mailer/mailer_generator.rb +30 -0
- data/lib/rails_generator/generators/components/mailer/templates/fixture.erb +3 -0
- data/lib/rails_generator/generators/components/mailer/templates/fixture.rhtml +0 -0
- data/lib/rails_generator/generators/components/mailer/templates/mailer.rb +15 -0
- data/lib/rails_generator/generators/components/mailer/templates/unit_test.rb +20 -0
- data/lib/rails_generator/generators/components/mailer/templates/view.erb +3 -0
- data/lib/rails_generator/generators/components/mailer/templates/view.rhtml +0 -0
- data/lib/rails_generator/generators/components/metal/USAGE +8 -0
- data/lib/rails_generator/generators/components/metal/metal_generator.rb +8 -0
- data/lib/rails_generator/generators/components/metal/templates/metal.rb +12 -0
- data/lib/rails_generator/generators/components/migration/USAGE +29 -0
- data/lib/rails_generator/generators/components/migration/migration_generator.rb +20 -0
- data/lib/rails_generator/generators/components/migration/templates/migration.rb +11 -0
- data/lib/rails_generator/generators/components/model/USAGE +27 -0
- data/lib/rails_generator/generators/components/model/model_generator.rb +52 -0
- data/lib/rails_generator/generators/components/model/templates/fixtures.yml +19 -0
- data/lib/rails_generator/generators/components/model/templates/migration.rb +16 -0
- data/lib/rails_generator/generators/components/model/templates/model.rb +5 -0
- data/lib/rails_generator/generators/components/model/templates/unit_test.rb +8 -0
- data/lib/rails_generator/generators/components/observer/USAGE +13 -0
- data/lib/rails_generator/generators/components/observer/observer_generator.rb +16 -0
- data/lib/rails_generator/generators/components/observer/templates/observer.rb +2 -0
- data/lib/rails_generator/generators/components/observer/templates/unit_test.rb +8 -0
- data/lib/rails_generator/generators/components/performance_test/USAGE +8 -0
- data/lib/rails_generator/generators/components/performance_test/performance_test_generator.rb +16 -0
- data/lib/rails_generator/generators/components/performance_test/templates/performance_test.rb +9 -0
- data/lib/rails_generator/generators/components/plugin/USAGE +25 -0
- data/lib/rails_generator/generators/components/plugin/plugin_generator.rb +39 -0
- data/lib/rails_generator/generators/components/plugin/templates/MIT-LICENSE +20 -0
- data/lib/rails_generator/generators/components/plugin/templates/README +13 -0
- data/lib/rails_generator/generators/components/plugin/templates/Rakefile +23 -0
- data/lib/rails_generator/generators/components/plugin/templates/USAGE +8 -0
- data/lib/rails_generator/generators/components/plugin/templates/generator.rb +8 -0
- data/lib/rails_generator/generators/components/plugin/templates/init.rb +1 -0
- data/lib/rails_generator/generators/components/plugin/templates/install.rb +1 -0
- data/lib/rails_generator/generators/components/plugin/templates/plugin.rb +1 -0
- data/lib/rails_generator/generators/components/plugin/templates/tasks.rake +4 -0
- data/lib/rails_generator/generators/components/plugin/templates/test_helper.rb +3 -0
- data/lib/rails_generator/generators/components/plugin/templates/uninstall.rb +1 -0
- data/lib/rails_generator/generators/components/plugin/templates/unit_test.rb +8 -0
- data/lib/rails_generator/generators/components/resource/USAGE +23 -0
- data/lib/rails_generator/generators/components/resource/resource_generator.rb +76 -0
- data/lib/rails_generator/generators/components/resource/templates/controller.rb +2 -0
- data/lib/rails_generator/generators/components/resource/templates/functional_test.rb +8 -0
- data/lib/rails_generator/generators/components/resource/templates/helper.rb +2 -0
- data/lib/rails_generator/generators/components/resource/templates/helper_test.rb +4 -0
- data/lib/rails_generator/generators/components/scaffold/USAGE +29 -0
- data/lib/rails_generator/generators/components/scaffold/scaffold_generator.rb +103 -0
- data/lib/rails_generator/generators/components/scaffold/templates/controller.rb +85 -0
- data/lib/rails_generator/generators/components/scaffold/templates/functional_test.rb +45 -0
- data/lib/rails_generator/generators/components/scaffold/templates/helper.rb +2 -0
- data/lib/rails_generator/generators/components/scaffold/templates/helper_test.rb +4 -0
- data/lib/rails_generator/generators/components/scaffold/templates/layout.html.erb +17 -0
- data/lib/rails_generator/generators/components/scaffold/templates/style.css +54 -0
- data/lib/rails_generator/generators/components/scaffold/templates/view_edit.html.erb +18 -0
- data/lib/rails_generator/generators/components/scaffold/templates/view_index.html.erb +24 -0
- data/lib/rails_generator/generators/components/scaffold/templates/view_new.html.erb +17 -0
- data/lib/rails_generator/generators/components/scaffold/templates/view_show.html.erb +10 -0
- data/lib/rails_generator/generators/components/session_migration/USAGE +10 -0
- data/lib/rails_generator/generators/components/session_migration/session_migration_generator.rb +18 -0
- data/lib/rails_generator/generators/components/session_migration/templates/migration.rb +16 -0
- data/lib/rails_generator/lookup.rb +249 -0
- data/lib/rails_generator/manifest.rb +53 -0
- data/lib/rails_generator/options.rb +150 -0
- data/lib/rails_generator/scripts.rb +89 -0
- data/lib/rails_generator/scripts/destroy.rb +29 -0
- data/lib/rails_generator/scripts/generate.rb +7 -0
- data/lib/rails_generator/scripts/update.rb +12 -0
- data/lib/rails_generator/secret_key_generator.rb +24 -0
- data/lib/rails_generator/simple_logger.rb +46 -0
- data/lib/rails_generator/spec.rb +44 -0
- data/lib/railties_path.rb +1 -0
- data/lib/ruby_version_check.rb +17 -0
- data/lib/rubyprof_ext.rb +35 -0
- data/lib/source_annotation_extractor.rb +102 -0
- data/lib/tasks/annotations.rake +20 -0
- data/lib/tasks/databases.rake +436 -0
- data/lib/tasks/documentation.rake +88 -0
- data/lib/tasks/framework.rake +143 -0
- data/lib/tasks/gems.rake +78 -0
- data/lib/tasks/log.rake +9 -0
- data/lib/tasks/middleware.rake +7 -0
- data/lib/tasks/misc.rake +63 -0
- data/lib/tasks/rails.rb +9 -0
- data/lib/tasks/routes.rake +18 -0
- data/lib/tasks/statistics.rake +17 -0
- data/lib/tasks/testing.rake +139 -0
- data/lib/tasks/tmp.rake +37 -0
- data/lib/test_help.rb +38 -0
- data/lib/webrick_server.rb +156 -0
- 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
|