Method: ActionController::ConditionalGet#fresh_when
- Defined in:
- actionpack/lib/action_controller/metal/conditional_get.rb
#fresh_when(object = nil, etag: nil, weak_etag: nil, strong_etag: nil, last_modified: nil, public: false, cache_control: {}, template: nil) ⇒ Object
Sets the ‘etag`, `last_modified`, or both on the response, and renders a `304 Not Modified` response if the request is already fresh.
#### Options
‘:etag` : Sets a “weak” ETag validator on the response. See the `:weak_etag` option.
‘:weak_etag` : Sets a “weak” ETag validator on the response. Requests that specify an
`If-None-Match` header may receive a `304 Not Modified` response if the
ETag matches exactly.
: A weak ETag indicates semantic equivalence, not byte-for-byte equality, so
they're good for caching HTML pages in browser caches. They can't be used
for responses that must be byte-identical, like serving `Range` requests
within a PDF file.
‘:strong_etag` : Sets a “strong” ETag validator on the response. Requests that specify an
`If-None-Match` header may receive a `304 Not Modified` response if the
ETag matches exactly.
: A strong ETag implies exact equality – the response must match byte for
byte. This is necessary for serving `Range` requests within a large video
or PDF file, for example, or for compatibility with some CDNs that don't
support weak ETags.
‘:last_modified` : Sets a “weak” last-update validator on the response. Subsequent requests
that specify an `If-Modified-Since` header may receive a `304 Not
Modified` response if `last_modified` <= `If-Modified-Since`.
‘:public` : By default the `Cache-Control` header is private. Set this option to
`true` if you want your application to be cacheable by other devices, such
as proxy caches.
‘:cache_control` : When given, will overwrite an existing `Cache-Control` header. For a list
of `Cache-Control` directives, see the [article on
MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control).
‘:template` : By default, the template digest for the current controller/action is
included in ETags. If the action renders a different template, you can
include its digest instead. If the action doesn't render a template at
all, you can pass `template: false` to skip any attempt to check for a
template digest.
#### Examples
def show
@article = Article.find(params[:id])
fresh_when(etag: @article, last_modified: @article.updated_at, public: true)
end
This will send a ‘304 Not Modified` response if the request specifies a matching ETag and `If-Modified-Since` header. Otherwise, it will render the `show` template.
You can also just pass a record:
def show
@article = Article.find(params[:id])
fresh_when(@article)
end
‘etag` will be set to the record, and `last_modified` will be set to the record’s ‘updated_at`.
You can also pass an object that responds to ‘maximum`, such as a collection of records:
def index
@articles = Article.all
fresh_when(@articles)
end
In this case, ‘etag` will be set to the collection, and `last_modified` will be set to `maximum(:updated_at)` (the timestamp of the most recently updated record).
When passing a record or a collection, you can still specify other options, such as ‘:public` and `:cache_control`:
def show
@article = Article.find(params[:id])
fresh_when(@article, public: true, cache_control: { no_cache: true })
end
The above will set ‘Cache-Control: public, no-cache` in the response.
When rendering a different template than the controller/action’s default template, you can indicate which digest to include in the ETag:
before_action { fresh_when @article, template: "widgets/show" }
137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 |
# File 'actionpack/lib/action_controller/metal/conditional_get.rb', line 137 def fresh_when(object = nil, etag: nil, weak_etag: nil, strong_etag: nil, last_modified: nil, public: false, cache_control: {}, template: nil) response.cache_control.delete(:no_store) weak_etag ||= etag || object unless strong_etag last_modified ||= object.try(:updated_at) || object.try(:maximum, :updated_at) if strong_etag response.strong_etag = strong_etag, last_modified: last_modified, public: public, template: template elsif weak_etag || template response.weak_etag = weak_etag, last_modified: last_modified, public: public, template: template end response.last_modified = last_modified if last_modified response.cache_control[:public] = true if public response.cache_control.merge!(cache_control) head :not_modified if request.fresh?(response) end |