Module: ExpoTurbo::Rails::Controller

Extended by:
ActiveSupport::Concern
Includes:
ActionController::Helpers, ActionView::Rendering
Defined in:
lib/expo_turbo/rails/controller.rb

Instance Method Summary collapse

Instance Method Details

#broadcast_expo_turbo_refresh_later_to(*streamables, request_id: ::Turbo.current_request_id, **attributes) ⇒ Object



275
276
277
# File 'lib/expo_turbo/rails/controller.rb', line 275

def broadcast_expo_turbo_refresh_later_to(*streamables, request_id: ::Turbo.current_request_id, **attributes)
  ExpoTurbo::Rails::Streams.broadcast_refresh_later_to(*streamables, request_id:, **attributes)
end

#broadcast_expo_turbo_refresh_to(*streamables, request_id: ::Turbo.current_request_id, **attributes) ⇒ Object



271
272
273
# File 'lib/expo_turbo/rails/controller.rb', line 271

def broadcast_expo_turbo_refresh_to(*streamables, request_id: ::Turbo.current_request_id, **attributes)
  ExpoTurbo::Rails::Streams.broadcast_refresh_to(*streamables, request_id:, **attributes)
end

#broadcast_expo_turbo_stream_later_to(*streamables, content: nil) ⇒ Object

Raises:

  • (ArgumentError)


263
264
265
266
267
268
269
# File 'lib/expo_turbo/rails/controller.rb', line 263

def broadcast_expo_turbo_stream_later_to(*streamables, content: nil)
  raise ArgumentError, "provide content or a block, not both" if block_given? && !content.nil?

  content = yield(expo_turbo_stream) if block_given?
  expo_turbo_validate_broadcast_stream!(content)
  ExpoTurbo::Rails::Streams.broadcast_later_to(*streamables, content: content)
end

#broadcast_expo_turbo_stream_to(*streamables, content: nil) ⇒ Object

Raises:

  • (ArgumentError)


255
256
257
258
259
260
261
# File 'lib/expo_turbo/rails/controller.rb', line 255

def broadcast_expo_turbo_stream_to(*streamables, content: nil)
  raise ArgumentError, "provide content or a block, not both" if block_given? && !content.nil?

  content = yield(expo_turbo_stream) if block_given?
  expo_turbo_validate_broadcast_stream!(content)
  ExpoTurbo::Rails::Streams.broadcast_to(*streamables, content: content)
end

#expo_turbo_cache_key(*keys) ⇒ Object



111
112
113
114
# File 'lib/expo_turbo/rails/controller.rb', line 111

def expo_turbo_cache_key(*keys)
  expo_turbo_vary_by_frame!
  [*keys, *expo_turbo_cache_variant]
end

#expo_turbo_cache_variantObject



95
96
97
98
99
# File 'lib/expo_turbo/rails/controller.rb', line 95

def expo_turbo_cache_variant
  negotiation = expo_turbo_module_negotiation
  module_variant = negotiation.fetch(:latest) ? :latest : negotiation.fetch(:cache_variant)
  [*Frames.cache_variant(expo_turbo_frame_request_id), :modules, module_variant]
end

#expo_turbo_client_modulesObject



73
74
75
# File 'lib/expo_turbo/rails/controller.rb', line 73

def expo_turbo_client_modules
  expo_turbo_module_negotiation.fetch(:modules)
end

#expo_turbo_client_supports?(module_name, requirement) ⇒ Boolean

Returns:

  • (Boolean)

Raises:

  • (ArgumentError)


77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
# File 'lib/expo_turbo/rails/controller.rb', line 77

def expo_turbo_client_supports?(module_name, requirement)
  raise ArgumentError, "module_name must be a String" unless module_name.is_a?(String)
  raise ArgumentError, "requirement must be a String" unless requirement.is_a?(String)
  raise ArgumentError, "requirement must not be empty" if requirement.strip.empty?

  requirement_parts = requirement.split(",", -1).map(&:strip)
  raise ArgumentError, "requirement must not contain empty clauses" if requirement_parts.any?(&:empty?)

  parsed_requirement = Gem::Requirement.new(*requirement_parts)
  negotiation = expo_turbo_module_negotiation
  return true if negotiation.fetch(:latest)

  version = negotiation.fetch(:modules)[module_name]
  return false unless version

  parsed_requirement.satisfied_by?(Gem::Version.new(version))
end

#expo_turbo_frame_request?Boolean

Returns:

  • (Boolean)


63
64
65
# File 'lib/expo_turbo/rails/controller.rb', line 63

def expo_turbo_frame_request?
  expo_turbo_frame_request_id.present?
end

#expo_turbo_frame_request_idObject



67
68
69
70
71
# File 'lib/expo_turbo/rails/controller.rb', line 67

def expo_turbo_frame_request_id
  frame_id = request.get_header("HTTP_TURBO_FRAME")
  frame_id = frame_id.dup.force_encoding(Encoding::UTF_8) if frame_id.is_a?(String)
  Frames.valid_id?(frame_id) ? frame_id : nil
end

#expo_turbo_streamObject



116
117
118
# File 'lib/expo_turbo/rails/controller.rb', line 116

def expo_turbo_stream
  view_context.expo_turbo_stream
end

#expo_turbo_vary_by_frame!Object



101
102
103
104
105
106
107
108
109
# File 'lib/expo_turbo/rails/controller.rb', line 101

def expo_turbo_vary_by_frame!
  values = response.headers["Vary"].to_s.split(",").map(&:strip).reject(&:blank?)
  return response.headers["Vary"] if values.include?("*")

  values << "Accept" if request.should_apply_vary_header? && values.none? { |value| value.casecmp?("Accept") }
  values << "Turbo-Frame" if values.none? { |value| value.casecmp?("Turbo-Frame") }
  values << "X-Expo-Turbo-Modules" if values.none? { |value| value.casecmp?("X-Expo-Turbo-Modules") }
  response.set_header "Vary", values.join(", ")
end

#render_expo_turbo(template, locals: {}, status: :ok) ⇒ Object



42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
# File 'lib/expo_turbo/rails/controller.rb', line 42

def render_expo_turbo(template, locals: {}, status: :ok)
  body = render_to_string(
    inline: File.read(expo_turbo_template_file(template)),
    type: :erb,
    formats: [:xml],
    layout: false,
    locals: locals
  )
  raise TemplateError, "Expo Turbo templates must render valid UTF-8" unless body.encoding == Encoding::UTF_8 && body.valid_encoding?

  document = XmlFragments.parse_document(body)
  XmlFragments.validate_document_ids!(document)
  expo_turbo_validate_document!(document)

  render plain: body, content_type: MIME_TYPE, status: status
rescue XmlFragments::DocumentIdError
  raise TemplateError, "Expo Turbo templates must use unique nonblank literal ids"
rescue XmlFragments::ParseError
  raise TemplateError, "Expo Turbo templates must render well-formed UTF-8 XML"
end

#render_expo_turbo_stream(*streams, status: :ok) ⇒ Object



242
243
244
245
246
247
248
249
250
251
252
253
# File 'lib/expo_turbo/rails/controller.rb', line 242

def render_expo_turbo_stream(*streams, status: :ok)
  streams << yield(expo_turbo_stream) if block_given?
  body = streams.flatten.compact.join
  raise TemplateError, "Expo Turbo Stream responses must render valid UTF-8" unless body.encoding == Encoding::UTF_8 && body.valid_encoding?

  document = XmlFragments.parse_stream_fragment(body)
  expo_turbo_validate_stream_fragment!(document)

  render plain: body, content_type: TURBO_STREAM_MIME_TYPE, status: status
rescue XmlFragments::ParseError
  raise TemplateError, "Expo Turbo Stream responses must contain well-formed XML Stream fragments"
end