Module: SolidObjects::Web::Helpers

Included in:
Action
Defined in:
lib/solid_objects/web/helpers.rb,
sig/generated/lib/solid_objects/web/helpers.rbs

Overview

The methods a view may call. Everything a template prints goes through h, because an actor id, an operation name, and an exception message are all application supplied strings that reach this page unchanged.

Constant Summary collapse

FORWARDED_PARAMS =

Only these survive a page link. A filter an operator set stays set when they turn the page; anything else the query string carries does not come back.

Returns:

  • (Object)
%w[actor_type actor_id status per_page].freeze
TRUNCATION_LIMIT =

Returns:

  • (::Integer)
2_000

Instance Method Summary collapse

Instance Method Details

#actor_label(record) ⇒ String

RBS:

  • (untyped) -> String

Parameters:

  • (Object)

Returns:

  • (String)


109
110
111
# File 'lib/solid_objects/web/helpers.rb', line 109

def actor_label(record)
  "#{h(record.actor_type)} / #{h(record.actor_id)}"
end

#chart(name, values) ⇒ String

Chart data travels in an attribute rather than an inline script block, so the page needs no script-src exception and an actor type cannot close the attribute and open a tag.

The container is not decoration. Chart.js measures a responsive canvas against its parent, so the parent has to have a height of its own; a panel that sizes to its children would grow a little on every redraw.

RBS:

  • (String, untyped) -> String

Parameters:

  • (String)
  • (Object)

Returns:

  • (String)


198
199
200
201
202
203
# File 'lib/solid_objects/web/helpers.rb', line 198

def chart(name, values)
  return "" unless Web.charts?

  %(<div class="chart-frame"><canvas data-chart="#{h(name)}" ) +
    %(data-chart-values='#{h(JSON.generate(values))}'></canvas></div>)
end

#chart_library_integrity_attributesString

RBS:

  • () -> String

Returns:

  • (String)


214
215
216
217
218
219
# File 'lib/solid_objects/web/helpers.rb', line 214

def chart_library_integrity_attributes
  integrity = Web.chart_library_integrity
  return "" unless integrity

  %( integrity="#{h(integrity)}" crossorigin="anonymous" referrerpolicy="no-referrer")
end

#chart_library_sourceString

A vendored copy is a path below the mount; a CDN copy is an absolute URL and is left alone.

RBS:

  • () -> String

Returns:

  • (String)


208
209
210
211
# File 'lib/solid_objects/web/helpers.rb', line 208

def chart_library_source
  url = Web.chart_library_url.to_s
  url.include?("//") ? url : path_to(url)
end

#csp_nonceString?

RBS:

  • () -> String?

Returns:

  • (String, nil)


51
52
53
# File 'lib/solid_objects/web/helpers.rb', line 51

def csp_nonce
  env[Web::NONCE_KEY]
end

#csrf_tagString

RBS:

  • () -> String

Returns:

  • (String)


56
57
58
# File 'lib/solid_objects/web/helpers.rb', line 56

def csrf_tag
  %(<input type="hidden" name="authenticity_token" value="#{h(env[Web::CSRF_TOKEN_KEY])}" />)
end

#current_pathString

RBS:

  • () -> String

Returns:

  • (String)


34
35
36
# File 'lib/solid_objects/web/helpers.rb', line 34

def current_path
  request.path_info
end

#current_tab?(path) ⇒ Boolean

RBS:

  • (String) -> bool

Parameters:

  • (String)

Returns:

  • (Boolean)


39
40
41
42
43
# File 'lib/solid_objects/web/helpers.rb', line 39

def current_tab?(path)
  return current_path == "/" if path == "/"

  current_path.start_with?(path)
end

#duration(seconds) ⇒ String

RBS:

  • (Numeric?) -> String

Parameters:

  • (Numeric, nil)

Returns:

  • (String)


79
80
81
82
83
84
85
# File 'lib/solid_objects/web/helpers.rb', line 79

def duration(seconds)
  return "&mdash;" unless seconds

  return "#{h(format("%.3f", seconds))} s" if seconds < 60

  h("#{(seconds / 60).floor} min #{(seconds % 60).round} s")
end

#environment_nameString

RBS:

  • () -> String

Returns:

  • (String)


222
223
224
# File 'lib/solid_objects/web/helpers.rb', line 222

def environment_name
  ENV["RAILS_ENV"] || ENV["RACK_ENV"] || "development"
end

#filter_value(allowed, default: nil) ⇒ String?

An unrecognized filter falls back to the default rather than returning nothing, so a hand edited query string cannot make a page look empty.

RBS:

  • (Array[String], ?default: String?) -> String?

Parameters:

  • (Array[String])
  • default: (String, nil) (defaults to: nil)

Returns:

  • (String, nil)


156
157
158
159
# File 'lib/solid_objects/web/helpers.rb', line 156

def filter_value(allowed, default: nil)
  value = url_params("status")
  allowed.include?(value) ? value : default
end

#filtered_instancesObject

RBS:

  • () -> untyped

Returns:

  • (Object)


170
171
172
173
174
175
176
177
178
179
180
# File 'lib/solid_objects/web/helpers.rb', line 170

def filtered_instances
  relation = Instance.order(updated_at: :desc, id: :desc)
  actor_type = url_params("actor_type")
  relation = relation.where(actor_type:) unless actor_type.to_s.empty?
  actor_id = url_params("actor_id")
  return relation if actor_id.to_s.empty?

  relation.where(
    Instance.arel_table[:actor_id].matches("%#{Instance.sanitize_sql_like(actor_id)}%")
  )
end

#find_instanceInstance

RBS:

  • () -> Instance

Returns:



162
163
164
165
166
167
# File 'lib/solid_objects/web/helpers.rb', line 162

def find_instance
  instance = Instance.find_by(id: route_params(:id))
  halt(404) unless instance

  instance
end

#form_to(path) ⇒ String

RBS:

  • (String) -> String

Parameters:

  • (String)

Returns:

  • (String)


61
62
63
# File 'lib/solid_objects/web/helpers.rb', line 61

def form_to(path)
  %(<form method="post" action="#{h(path_to(path))}">#{csrf_tag})
end

#h(text) ⇒ String

RBS:

  • (untyped) -> String

Parameters:

  • (Object)

Returns:

  • (String)


19
20
21
# File 'lib/solid_objects/web/helpers.rb', line 19

def h(text)
  ::Rack::Utils.escape_html(text.to_s)
end

RBS:

  • (untyped) -> String

Parameters:

  • (Object)

Returns:

  • (String)


114
115
116
# File 'lib/solid_objects/web/helpers.rb', line 114

def instance_link(instance)
  %(<a href="#{h(path_to("/instances/#{instance.id}"))}">#{actor_label(instance)}</a>)
end

#json_block(value) ⇒ String

RBS:

  • (untyped, ?Integer) -> String

Parameters:

  • (Object)
  • (Integer)

Returns:

  • (String)


88
89
90
91
92
93
94
# File 'lib/solid_objects/web/helpers.rb', line 88

def json_block(value)
  return "&mdash;" if value.nil?

  %(<pre class="payload">#{h(truncate(JSON.pretty_generate(value)))}</pre>)
rescue JSON::GeneratorError, TypeError
  %(<pre class="payload">#{h(truncate(value.inspect))}</pre>)
end

#lease_state(instance) ⇒ String

RBS:

  • (Instance) -> String

Parameters:

Returns:

  • (String)


135
136
137
138
139
140
141
# File 'lib/solid_objects/web/helpers.rb', line 135

def lease_state(instance)
  return "paused" if instance.paused_at
  return "idle" unless instance.activation_owner_id
  return "idle" unless instance.activation_expires_at

  (instance.activation_expires_at > statistics.now) ? "activated" : "expired"
end

#mailbox_messages(membership) ⇒ Object

RBS:

  • (String) -> untyped

Parameters:

  • (String)

Returns:

  • (Object)


183
184
185
186
187
188
# File 'lib/solid_objects/web/helpers.rb', line 183

def mailbox_messages(membership)
  membership_model = (membership == "claimed") ? ClaimedMessage : ReadyMessage
  Message
    .where(id: membership_model.select(:message_id))
    .order(available_at: :asc, id: :asc)
end

#number(value) ⇒ String

RBS:

  • (untyped) -> String

Parameters:

  • (Object)

Returns:

  • (String)


74
75
76
# File 'lib/solid_objects/web/helpers.rb', line 74

def number(value)
  h(value.to_i.to_s.reverse.scan(/\d{1,3}/).join(",").reverse)
end

RBS:

  • (?Hash[String, untyped]) -> String

Parameters:

  • (Hash[String, untyped])

Returns:

  • (String)


130
131
132
# File 'lib/solid_objects/web/helpers.rb', line 130

def page_link(overrides = {})
  h("#{path_to(current_path)}#{query_string(overrides)}")
end

#paginate(relation) ⇒ Paginator

RBS:

  • (untyped) -> Paginator

Parameters:

  • (Object)

Returns:



149
150
151
# File 'lib/solid_objects/web/helpers.rb', line 149

def paginate(relation)
  Paginator.new(relation:, page: url_params("page"), per_page: url_params("per_page"))
end

#path_to(path) ⇒ String

RBS:

  • (String) -> String

Parameters:

  • (String)

Returns:

  • (String)


29
30
31
# File 'lib/solid_objects/web/helpers.rb', line 29

def path_to(path)
  "#{root_path}#{path}"
end

#query_string(overrides = {}) ⇒ String

RBS:

  • (?Hash[String, untyped]) -> String

Parameters:

  • (Hash[String, untyped])

Returns:

  • (String)


119
120
121
122
123
124
125
126
127
# File 'lib/solid_objects/web/helpers.rb', line 119

def query_string(overrides = {})
  merged = FORWARDED_PARAMS
    .to_h { |name| [ name, url_params(name) ] }
    .merge(overrides.transform_keys(&:to_s))
    .reject { |_name, value| value.nil? || value.to_s.empty? }
  return "" if merged.empty?

  "?#{merged.map { |name, value| "#{::Rack::Utils.escape(name)}=#{::Rack::Utils.escape(value.to_s)}" }.join("&")}"
end

#relative_time(time) ⇒ String

RBS:

  • (untyped) -> String

Parameters:

  • (Object)

Returns:

  • (String)


66
67
68
69
70
71
# File 'lib/solid_objects/web/helpers.rb', line 66

def relative_time(time)
  return "&mdash;" unless time

  stamp = time.getutc.iso8601
  %(<time datetime="#{stamp}" title="#{stamp}">#{h(stamp)}</time>)
end

#root_pathString

RBS:

  • () -> String

Returns:

  • (String)


24
25
26
# File 'lib/solid_objects/web/helpers.rb', line 24

def root_path
  env["SCRIPT_NAME"].to_s
end

#statisticsStatistics

RBS:

  • () -> Statistics

Returns:



144
145
146
# File 'lib/solid_objects/web/helpers.rb', line 144

def statistics
  @statistics ||= Statistics.new
end

#status_label(status) ⇒ String

RBS:

  • (String?) -> String

Parameters:

  • (String, nil)

Returns:

  • (String)


104
105
106
# File 'lib/solid_objects/web/helpers.rb', line 104

def status_label(status)
  %(<span class="status status-#{h(status)}">#{h(status)}</span>)
end

#tabsHash[String, String]

RBS:

  • () -> Hash[String, String]

Returns:

  • (Hash[String, String])


46
47
48
# File 'lib/solid_objects/web/helpers.rb', line 46

def tabs
  Web.tabs
end

#truncate(text, limit = TRUNCATION_LIMIT) ⇒ String

RBS:

  • (String, ?Integer) -> String

Parameters:

  • (String)
  • (Integer)

Returns:

  • (String)


97
98
99
100
101
# File 'lib/solid_objects/web/helpers.rb', line 97

def truncate(text, limit = TRUNCATION_LIMIT)
  return text if text.length <= limit

  "#{text[0, limit]}"
end