Class: Redirect

Inherits:
ApplicationRecord
  • Object
show all
Includes:
Discard::Model, PgSearch::Model, Ransackable
Defined in:
lib/generators/ruby_cms/templates/models/redirect.rb

Overview

Redirect rules served by RedirectMiddleware.

  • source_path is normalized (downcased, trailing slash stripped) so we never miss a hit because of casing or a trailing "/".
  • target_path is optional only for 410 (Gone) rules.
  • lookup is cached in Rails.cache for the request hot path; create/update/ destroy bust the entire redirect:* namespace via expire_cache.

Constant Summary collapse

STATUS_CODES =
[ 301, 302, 410 ].freeze

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.bust_cache(_path = nil) ⇒ Object

Convenience for ad-hoc cache busting (also called by callbacks).



46
47
48
49
50
51
# File 'lib/generators/ruby_cms/templates/models/redirect.rb', line 46

def self.bust_cache(_path = nil)
  Rails.cache.delete_matched("redirect:*")
rescue NotImplementedError
  # MemoryStore in test/dev supports delete_matched; some stores don't.
  Rails.cache.clear
end

.compute_lookup(path) ⇒ Object



65
66
67
68
69
70
71
72
73
74
75
# File 'lib/generators/ruby_cms/templates/models/redirect.rb', line 65

def self.compute_lookup(path)
  rule = active.where("LOWER(source_path::text) = ?", path).first

  rule ||= active
    .where("source_path::text LIKE '%*'")
    .find { |r| wildcard_match?(r.source_path.to_s.downcase, path) }

  return nil unless rule

  { id: rule.id, target: rule.target_path, status_code: rule.status_code }
end

.lookup(path) ⇒ Object



36
37
38
39
40
41
42
43
# File 'lib/generators/ruby_cms/templates/models/redirect.rb', line 36

def self.lookup(path)
  return nil if path.blank?

  key = normalize_path_for_lookup(path)
  Rails.cache.fetch("redirect:#{key}", expires_in: 5.minutes) do
    compute_lookup(key)
  end
end

.normalize_path_for_lookup(path) ⇒ Object



59
60
61
62
63
# File 'lib/generators/ruby_cms/templates/models/redirect.rb', line 59

def self.normalize_path_for_lookup(path)
  p = path.to_s.downcase
  p = p.chomp("/") if p.length > 1 && p.end_with?("/")
  p
end

.wildcard_match?(pattern, path) ⇒ Boolean

Returns:

  • (Boolean)


77
78
79
80
# File 'lib/generators/ruby_cms/templates/models/redirect.rb', line 77

def self.wildcard_match?(pattern, path)
  prefix = pattern.chomp("*")
  path.start_with?(prefix)
end

Instance Method Details

#gone?Boolean

Returns:

  • (Boolean)


53
54
55
# File 'lib/generators/ruby_cms/templates/models/redirect.rb', line 53

def gone?
  status_code.to_i == 410
end