Module: Sinatra::Cache
- Defined in:
- lib/sinatra/cache/helpers.rb,
lib/sinatra/cache.rb
Overview
Sinatra::Cache
A Sinatra Extension that makes Page and Fragment Caching easy wthin your Sinatra apps.
Installation
# Add RubyGems.org (former Gemcutter) to your RubyGems sources
$ gem sources -a http://rubygems.org
$ (sudo)? gem install sinatra-cache
Dependencies
This Gem depends upon the following:
Runtime:
-
sinatra ( >= 1.0.a )
-
sinatra-outputbuffer (>= 0.1.0)
Optionals:
-
sinatra-settings (>= 0.1.1) # to view default settings in a browser display.
Development & Tests:
-
rspec (>= 1.3.0 )
-
rack-test (>= 0.5.3)
-
rspec_hpricot_matchers (>= 0.1.0)
-
sinatra-tests (>= 0.1.6)
-
fileutils
-
sass
-
ostruct
-
yaml
-
json
Getting Started
To start caching your app’s ouput, just require and register the extension in your sub-classed Sinatra app:
require 'sinatra/cache'
class YourApp < Sinatra::Base
# NB! you need to set the root of the app first
set :root, '/path/2/the/root/of/your/app'
register(Sinatra::Cache)
set :cache_enabled, true # turn it on
<snip...>
end
That’s more or less it.
You should now be caching your output by default, in :production
mode, as long as you use one of Sinatra’s render methods:
erb(), erubis(), haml(), sass(), builder(), etc..
…or any render method that uses Sinatra::Templates#render()
as its base.
Configuration Settings
The default settings should help you get moving quickly, and are fairly common sense based.
:cache_enabled
This setting toggles the cache functionality On / Off. Default is: false
:cache_environment
Sets the environment during which the cache functionality is active. Default is: :production
:cache_page_extension
+
Sets the default file extension for cached files. Default is: .html
:cache_output_dir
Sets cache directory where the cached files are stored. Default is: == “/path/2/your/app/public”
Although you can set it to the more ideal ‘..public/system/cache/
’ if you can get that to work with your webserver setup.
:cache_fragments_output_dir
Sets the directory where cached fragments are stored. Default is the ‘../tmp/cache_fragments/’ directory at the root of your app.
This is for security reasons since you don’t really want your cached fragments publically available.
:cache_fragments_wrap_with_html_comments
This setting toggles the wrapping of cached fragments in HTML comments. (see below) Default is: true
:cache_logging
This setting toggles the logging of various cache calls. If the app has access to the #logger
method, curtesy of Sinatra::Logger then it will log there, otherwise logging is silent.
Default is: true
:cache_logging_level
Sets the level at which the cache logger should log it’s messages. Default is: :info
Available options are: [:fatal, :error, :warn, :info, :debug]
Basic Page Caching
By default caching only happens in :production
mode, and via the Sinatra render methods, erb(), etc,
So asuming we have the following setup (continued from above)
class YourApp
<snip...>
set :cache_output_dir, "/full/path/2/app/root/public/system/cache"
<snip...>
get('/') { erb(:index) } # => is cached as '../index.html'
get('/contact') { erb(:contact) } # => is cached as '../contact.html'
# NB! the trailing slash on the URL
get('/about/') { erb(:about) } # => is cached as '../about/index.html'
get('/feed.rss') { builder(:feed) } # => is cached as '../feed.rss'
# NB! uses the extension of the passed URL,
# but DOES NOT ensure the format of the content based on the extension provided.
# complex URL with multiple possible params
get %r{/articles/?([\s\w-]+)?/?([\w-]+)?/?([\w-]+)?/?([\w-]+)?/?([\w-]+)?/?([\w-]+)?} do
erb(:articles)
end
# with the '/articles/a/b/c => is cached as ../articles/a/b/c.html
# NB! the trailing slash on the URL
# with the '/articles/a/b/c/ => is cached as ../articles/a/b/c/index.html
# CSS caching via Sass # => is cached as '.../css/screen.css'
get '/css/screen.css' do
content_type 'text/css'
sass(:'css/screen')
end
# to turn off caching on certain pages.
get('/dont/cache/this/page') { erb(:aview, :cache => false) } # => is NOT cached
# NB! any query string params - [ /?page=X&id=y ] - are stripped off and TOTALLY IGNORED
# during the caching process.
end
OK, that’s about all you need to know about basic Page Caching right there. Read the above example carefully until you understand all the variations.
Fragment Caching
If you just need to cache a fragment of a page, then you would do as follows:
class YourApp
set :cache_fragments_output_dir, "/full/path/2/fragments/store/location"
end
Then in your views / layouts add the following:
<% cache_fragment(:name_of_fragment) do %>
# do something worth caching
<% end %>
Each fragment is stored in the same directory structure as your request so, if you have a request like this:
get '/articles/2010/02' ...
…the cached fragment will be stored as:
../tmp/cache_fragments/articles/2010/02/< name_of_fragment >.html
This enables you to use similar names for your fragments or have multiple URLs use the same view / layout.
An important limitation
The fragment caching is dependent upon the final URL, so in the case of a blog, where each article uses the same view, but through different URLs, each of the articles would cache it’s own fragment, which is ineffecient.
To sort-of deal with this limitation I have temporarily added a very hackish ‘fix’ through adding a 2nd parameter (see example below), which will remove the last part of the URL and use the rest of the URL as the stored fragment path.
So given the URL:
get '/articles/2010/02/fragment-caching-with-sinatra-cache' ...
and the following #cache_fragment
declaration in your view
<% cache_fragment(:name_of_fragment, :shared) do %>
# do something worth caching
<% end %>
…the cached fragment would be stored as:
../tmp/cache_fragments/articles/2010/02/< name_of_fragment >.html
Any other URLs with the same URL root, like…
get '/articles/2010/02/writing-sinatra-extensions' ...
… would use the same cached fragment.
NB! currently only supports one level, but Your fork might fix that ;-)
Cache Expiration
Under development, and not entirely final. See Todo’s below for more info.
To expire a cached item - file or fragment - you use the :cache_expire() method.
cache_expire('/contact') => expires ../contact.html
# NB! notice the trailing slash
cache_expire('/contact/') => expires ../contact/index.html
cache_expire('/feed.rss') => expires ../feed.rss
To expire a cached fragment:
cache_expire('/some/path', :fragment => :name_of_fragment )
=> expires ../some/path/:name_of_fragment.html
A few important points to consider
The DANGERS of URL query string params
By default the caching ignores the query string params, but that’s not the only problem with query params.
Let’s say you have a URL like this:
/products/?product_id=111
and then inside that template [ …/views/products.erb ], you use the params[:product_id]
param passed in for some purpose.
<ul>
<li>Product ID: <%= params[:product_id] %></li> # => 111
...
</ul>
If you cache this URL, then the cached file [ ../cache/products.html ] will be stored with that value embedded. Obviously not ideal for any other similar URLs with different product_id
‘s
To overcome this issue, use either of these two methods.
# in your_app.rb
# turning off caching on this page
get '/products/' do
...
erb(:products, :cache => false)
end
# or
# rework the URLs to something like '/products/111 '
get '/products/:product_id' do
...
erb(:products)
end
Thats’s about all the information you need to know.
Defined Under Namespace
Modules: Helpers
Constant Summary collapse
- VERSION =
'0.3.7'
Class Method Summary collapse
-
.registered(app) ⇒ Object
The default options:.
- .version ⇒ Object
Class Method Details
.registered(app) ⇒ Object
The default options:
-
:cache_enabled
=> toggle for the cache functionality. Default is:false
-
:cache_environment
=> sets the environment during which to cache. Default is::production
-
:cache_page_extension
=> sets the default extension for cached files. Default is:.html
-
:cache_output_dir
=> sets cache directory where cached files are stored. Default is: == “/path/2/your/app/public” Although you can set it to the more ideal ‘..public/system/cache/
’ if you can get that to work with your webserver setup. -
:cache_fragments_output_dir
=> sets the directory where cached fragments are stored. Default is the ‘../tmp/cache_fragments/’ directory at the root of your app. -
:cache_fragments_wrap_with_html_comments
=> toggle for wrapping the cached fragment in HTML comments. Default is:true
-
:cache_logging
=> toggle for logging the cache calls. Default is:true
-
:cache_logging_level
=> sets the level of the cache logger. Default is::info
.
Available options are: [:fatal, :error, :warn, :info, :debug]
635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 |
# File 'lib/sinatra/cache/helpers.rb', line 635 def self.registered(app) app.register(Sinatra::OutputBuffer) app.helpers Cache::Helpers ## CONFIGURATIONS:: app.set :cache_enabled, false app.set :cache_environment, :production app.set :cache_page_extension, '.html' app.set :cache_output_dir, lambda { app.public } app.set :cache_fragments_output_dir, lambda { "#{app.root}/tmp/cache_fragments" } app.set :cache_fragments_wrap_with_html_comments, true app.set :cache_logging, true app.set :cache_logging_level, :info ## add the extension specific options to those inspectable by :settings_inspect method if app.respond_to?(:sinatra_settings_for_inspection) %w( cache_enabled cache_environment cache_page_extension cache_output_dir cache_fragments_output_dir cache_fragments_wrap_with_html_comments cache_logging cache_logging_level ).each do |m| app.sinatra_settings_for_inspection << m end end end |
.version ⇒ Object
7 |
# File 'lib/sinatra/cache.rb', line 7 def self.version; "Sinatra::Cache v#{VERSION}"; end |