Class: Consently::Consent

Inherits:
Object
  • Object
show all
Defined in:
lib/consently/consent.rb

Overview

What the visitor has agreed to, as read from the cookie.

The cookie is deliberately tiny and readable by JavaScript - the banner writes it in the browser and the server only reads it, so a page rendered after the choice can emit the real tags instead of blocked ones.

{"v":1,"c":["analytics"],"t":"2026-08-12T10:00:00Z"}

Constant Summary collapse

NECESSARY =
:necessary

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(categories: [], version: nil, recorded_at: nil, given: true) ⇒ Consent

Returns a new instance of Consent.



54
55
56
57
58
59
# File 'lib/consently/consent.rb', line 54

def initialize(categories: [], version: nil, recorded_at: nil, given: true)
  @categories = Array(categories).map(&:to_sym).freeze
  @version = version
  @recorded_at = recorded_at
  @given = given
end

Instance Attribute Details

#categoriesObject (readonly)

Returns the value of attribute categories.



12
13
14
# File 'lib/consently/consent.rb', line 12

def categories
  @categories
end

#recorded_atObject (readonly)

Returns the value of attribute recorded_at.



12
13
14
# File 'lib/consently/consent.rb', line 12

def recorded_at
  @recorded_at
end

#versionObject (readonly)

Returns the value of attribute version.



12
13
14
# File 'lib/consently/consent.rb', line 12

def version
  @version
end

Class Method Details

.expired?(recorded_at, max_age) ⇒ Boolean

A consent older than max_age is asked for again, whatever the cookie's own expiry says. An unreadable timestamp is treated as too old: the only safe reading when we cannot tell when it was given.

Returns:

  • (Boolean)


45
46
47
48
49
50
51
52
# File 'lib/consently/consent.rb', line 45

def self.expired?(recorded_at, max_age)
  return false if max_age.nil?
  return true if recorded_at.blank?

  Time.parse(recorded_at.to_s) < Time.now.utc - max_age.to_i
rescue ArgumentError
  true
end

Never raises: a cookie can be truncated, hand-edited or left over from an older format, and none of that should take a page down.



20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# File 'lib/consently/consent.rb', line 20

def self.from_cookie(raw, version:, max_age: nil)
  return none if raw.blank?

  data = begin
    JSON.parse(raw.to_s)
  rescue JSON::ParserError
    nil
  end
  return none unless data.is_a?(Hash)

  # A consent given against an older policy version counts as no consent:
  # the banner asks again and nothing runs in the meantime.
  return none unless data["v"].to_s == version.to_s
  return none if expired?(data["t"], max_age)

  new(
    categories: Array(data["c"]).map { |category| category.to_s.to_sym },
    version: data["v"],
    recorded_at: data["t"]
  )
end

.noneObject



14
15
16
# File 'lib/consently/consent.rb', line 14

def self.none
  new(given: false)
end

Instance Method Details

#given?Boolean

Returns:

  • (Boolean)


61
62
63
# File 'lib/consently/consent.rb', line 61

def given?
  @given
end

#granted?(category) ⇒ Boolean

Necessary tags are the ones the site cannot work without, so they never wait for a click.

Returns:

  • (Boolean)


67
68
69
# File 'lib/consently/consent.rb', line 67

def granted?(category)
  category.to_sym == NECESSARY || categories.include?(category.to_sym)
end

#to_hObject



71
72
73
# File 'lib/consently/consent.rb', line 71

def to_h
  { "v" => version, "c" => categories.map(&:to_s), "t" => recorded_at }
end