Class: Decidim::ShortLink

Inherits:
ApplicationRecord show all
Defined in:
decidim-core/app/models/decidim/short_link.rb

Overview

Short links are a way to reference specific locations within Decidim with shorted URLs, similar to the popular link shortening services. The original reason for creating the feature was to reference long calendar URLs in a more compact way for the URLs to be compatible with the calendar programs. When the URL is long with lots of filtering parameters included in it, it may be too long for specific 3rd party programs.

This feature can be used to link to any URLs or resources in Decidim with a short reference.

Defined Under Namespace

Classes: OutOfCandidatesError

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.to(target, mounted_engine, route_name: nil, params: {}) ⇒ Decidim::ShortLink

Finds a matching short link to the same target with exactly the same parameters if it already exists or creates a new one if it does not exist.



35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
# File 'decidim-core/app/models/decidim/short_link.rb', line 35

def self.to(target, mounted_engine, route_name: nil, params: {})
  organization =
    if target.is_a?(Decidim::Organization)
      target
    else
      target.try(:organization)
    end

  values = {
    organization:,
    target:,
    mounted_engine_name: mounted_engine,
    route_name:
  }
  existing =
    if params
      where(values).find_by("params = ?::jsonb", params.to_json)
    else
      find_by(values.merge(params: nil))
    end

  existing || create!(values.merge(params:))
end

.unique_identifier_within(organization) ⇒ String

Creates a random unique identifier for any new links. Raises an OutOfCandidatesError if a free candidate cannot be found with 20 tries. In this situation the older records should be removed from the database.



64
65
66
67
68
69
70
71
72
73
74
75
76
# File 'decidim-core/app/models/decidim/short_link.rb', line 64

def self.unique_identifier_within(organization)
  1.step do |n|
    raise OutOfCandidatesError if n > 20

    # A-Z, a-z and 0-9
    # 26 + 26 + 10 = 62 possibilities per character
    # 62^10 ≈ 8×10¹⁷ total possibilities
    candidate = SecureRandom.alphanumeric(10)
    next if where(organization:, identifier: candidate).any?

    return candidate
  end
end

Instance Method Details

#route_nameString

Overrides the route_name method to add a default route name for the “root” path in case the route name is not defined for the record.



82
83
84
# File 'decidim-core/app/models/decidim/short_link.rb', line 82

def route_name
  super || "root"
end

#short_urlString

Generates the short URL referencing this link.



89
90
91
# File 'decidim-core/app/models/decidim/short_link.rb', line 89

def short_url
  EngineRouter.new("decidim", default_url_options).short_link_url(id: identifier)
end

#target_urlString

Generates the full long URL to the resource matching this short link.



96
97
98
# File 'decidim-core/app/models/decidim/short_link.rb', line 96

def target_url
  url_helpers.send("#{route_name}_url", **params)
end