Module: Merb::ConditionalGetMixin

Included in:
Controller
Defined in:
lib/merb-core/controller/mixins/conditional_get.rb

Overview

Provides conditional get support in Merb core. Conditional get support is intentionally simple and does not do fancy stuff like making ETag value from Ruby objects for you.

The most interesting method for end user is request_fresh? that is used after setting of last modification time or ETag:

Examples:

def show
  self.etag = Digest::SHA1.hexdigest(calculate_cache_key(params))

  if request_fresh?
    self.status = 304
    return ''
  else
    @product = Product.get(params[:id])
    display @product
  end
end

Instance Method Summary collapse

Instance Method Details

#etagString?

Value of the ETag header

Returns:

  • (String)

    Value of ETag response header if set.

  • (nil)

    If ETag header not set.



42
43
44
# File 'lib/merb-core/controller/mixins/conditional_get.rb', line 42

def etag
  headers[Merb::Const::ETAG]
end

#etag=(tag) ⇒ String

Sets ETag response header by calling #to_s on the argument

Parameters:

  • tag (#to_s)

    value of ETag header

Returns:

  • (String)

    value of ETag header enclosed in double quotes as required by the RFC



32
33
34
# File 'lib/merb-core/controller/mixins/conditional_get.rb', line 32

def etag=(tag)
  headers[Merb::Const::ETAG] = %("#{tag}")
end

#etag_matches?(tag = self.etag) ⇒ true

Test to see if the request’s Etag matches the one supplied locally

Returns:

  • (true)

    if ETag response header equals If-None-Match request header

  • (true)

    if it does not.



52
53
54
# File 'lib/merb-core/controller/mixins/conditional_get.rb', line 52

def etag_matches?(tag = self.etag)
  tag == self.request.if_none_match
end

#last_modifiedTime?

Value of the Last-Modified header

Returns:

  • (Time)

    Value of Last-Modified response header if set.

  • (nil)

    If Last-Modified not set.



75
76
77
78
# File 'lib/merb-core/controller/mixins/conditional_get.rb', line 75

def last_modified
  last_mod = headers[Merb::Const::LAST_MODIFIED]
  Time.rfc2822(last_mod) if last_mod
end

#last_modified=(time) ⇒ String

Sets Last-Modified response header

Parameters:

  • time (Time, DateTime)

    The last modified time of the resource

Returns:

  • (String)

    The last modified time of the resource in the format required by the RFC



63
64
65
66
67
# File 'lib/merb-core/controller/mixins/conditional_get.rb', line 63

def last_modified=(time)
  time = time.to_time if time.is_a?(DateTime)
  # time.utc.strftime("%a, %d %b %Y %X") if we could rely on locale being American
  headers[Merb::Const::LAST_MODIFIED] = time.httpdate
end

#not_modified?(time = self.last_modified) ⇒ true, false

Test to see if the request’s If-Modified-Since is satisfied

Parameters:

  • time (Time) (defaults to: self.last_modified)

    Time to test if the If-Modified-Since header against

Returns:

  • (true)

    Last-Modified response header is < than If-Modified-Since request header

  • (false)

    otherwise



88
89
90
91
92
93
94
# File 'lib/merb-core/controller/mixins/conditional_get.rb', line 88

def not_modified?(time = self.last_modified)
  if !request.if_modified_since.nil? and !time.nil?
    time <= request.if_modified_since
  else
    false
  end
end

#request_fresh?true, false

Tests freshness of response using all supplied validators

A response with no validators is always stale.

Returns:

  • (true)

    ETag matches and entity is not modified

  • (false)

    One or more validators failed, or none were supplied



104
105
106
107
108
109
110
111
112
113
114
# File 'lib/merb-core/controller/mixins/conditional_get.rb', line 104

def request_fresh?
  # make sure we have something to compare too.
  return false unless last_modified or etag

  fresh = true

  # only check if we have set the right headers
  fresh &&= etag_matches?(self.etag) if etag
  fresh &&= not_modified?(self.last_modified) if last_modified
  fresh
end