Module: SwalRails::Helpers

Defined in:
lib/swal_rails/helpers.rb

Overview

View helpers exposed to ActionView and ActionController.

Place ‘swal_rails_meta_tags` in your layout `<head>` to emit:

- the global client config (once per request)
- the per-request flash payload

Instance Method Summary collapse

Instance Method Details

#build_flash_payloadObject

Rails idiom: ‘flash = model.errors.full_messages` — expand arrays into one entry per message so each fires its own Swal.

Also accepts per-request option overrides:

flash[:notice] = "Saved"                                       # string shortcut
flash[:notice] = { text: "Saved", icon: "star", timer: 5000 }  # full SA2 options


36
37
38
39
40
41
42
43
44
45
# File 'lib/swal_rails/helpers.rb', line 36

def build_flash_payload
  flash.to_h.flat_map do |key, message|
    flash_messages(message).filter_map do |m|
      next if m.blank?

      options = m.is_a?(Hash) ? m.symbolize_keys : { text: m.to_s }
      { key: key.to_s, options: options }
    end
  end
end

#flash_messages(message) ⇒ Object

Arrays expand into one entry per element. A Hash is a single entry —don’t let ‘Array(hash)` destructure it into key/value pairs.



49
50
51
# File 'lib/swal_rails/helpers.rb', line 49

def flash_messages(message)
  message.is_a?(Array) ? message : [message]
end

#swal_chain_tag(steps, html_options = {}) ⇒ Object

Fires a multi-step confirm chain inline on page load.

Usage: ‘<%= swal_chain_tag([{ title: “Sure?” }, { title: “Really?” }]) %>` Under a strict CSP: `<%= swal_chain_tag(steps, nonce: true) %>`

Same XSS hardening and CSP nonce handling as ‘swal_tag`. Each step is a full SweetAlert2 options Hash; `onConfirmed:` / `onDenied:` keys declare nested sub-chains for conditional branching.



81
82
83
84
85
86
87
88
89
90
91
92
93
94
# File 'lib/swal_rails/helpers.rb', line 81

def swal_chain_tag(steps, html_options = {})
  # Array(hash) destructures a Hash into [[k, v], ...] pairs — wrap
  # single Hash steps manually so shorthand `swal_chain_tag(title: "Hi")`
  # produces `[{"title":"Hi"}]`, not `[["title","Hi"]]`.
  steps = [steps] unless steps.is_a?(Array)
  payload = ERB::Util.json_escape(steps.to_json)
  tag_options = { type: "module" }.merge(html_options)
  tag_options.delete(:nonce) if tag_options[:nonce] == true && !respond_to?(:content_security_policy_nonce, true)
  javascript_tag(<<~JS.strip, **tag_options)
    import Swal from "sweetalert2";
    import { chainDialogs } from "swal_rails/chain";
    chainDialogs(Swal, #{payload});
  JS
end

#swal_config_meta_tagObject



15
16
17
18
# File 'lib/swal_rails/helpers.rb', line 15

def swal_config_meta_tag
  payload = SwalRails.configuration.to_client_payload
  tag.meta(name: "swal-config", content: payload.to_json)
end

#swal_flash_meta_tagObject



20
21
22
23
24
25
26
27
28
# File 'lib/swal_rails/helpers.rb', line 20

def swal_flash_meta_tag
  return unless SwalRails.configuration.flash_keys_as_meta
  return if flash.blank?

  payload = build_flash_payload
  return if payload.empty?

  tag.meta(name: "swal-flash", content: payload.to_json)
end

#swal_rails_meta_tagsObject

Emits the two meta tags the JS runtime reads on boot.



11
12
13
# File 'lib/swal_rails/helpers.rb', line 11

def swal_rails_meta_tags
  safe_join([swal_config_meta_tag, swal_flash_meta_tag].compact, "\n")
end

#swal_tag(options = {}, html_options = {}) ⇒ Object

Generates an inline ‘<script>` that fires a single Swal.

Usage: ‘<%= swal_tag(title: “Hi”, icon: “info”) %>` Under a strict CSP: `<%= swal_tag({ title: “Hi” }, nonce: true) %>`

When ‘nonce: true` is passed and ActionView’s CSP helper is available, Rails substitutes the per-request nonce so the tag survives a ‘script-src ’self’ ‘nonce-…’‘ policy.



61
62
63
64
65
66
67
68
69
70
71
# File 'lib/swal_rails/helpers.rb', line 61

def swal_tag(options = {}, html_options = {})
  # json_escape neutralizes `</script>`, `<!--`, U+2028 and U+2029 —
  # the four sequences that can break out of a <script> block.
  payload = ERB::Util.json_escape(options.to_json)
  tag_options = { type: "module" }.merge(html_options)
  tag_options.delete(:nonce) if tag_options[:nonce] == true && !respond_to?(:content_security_policy_nonce, true)
  javascript_tag(<<~JS.strip, **tag_options)
    import Swal from "sweetalert2";
    Swal.fire(#{payload});
  JS
end