Skip to content

Instantly share code, notes, and snippets.

@gamecreature
Created August 6, 2021 14:49
Show Gist options
  • Save gamecreature/ec4c97c89748dfa1cfa79015200e04cb to your computer and use it in GitHub Desktop.
Save gamecreature/ec4c97c89748dfa1cfa79015200e04cb to your computer and use it in GitHub Desktop.
Chain turbo-stream responses from controllers (and auto append flash messages)
#
# What does this do:
#
# Normal: (Basic library usage, without this helper)
# --------------------------------------------------
# render turbo_stream: [
# turbo_stream.replace(:flash, partial: 'shared/flash'),
# turbo_stream.replace(:object, partial: 'partial/name', locals: { object: object } )
# turbo_stream.replace(:object2, partial: 'partial/name'2, locals: { object2: object2 } )
# ]
#
# Optimized 1: (flash is included, methods are chainable)
# -------------------------------------------------------
# render turbo_stream: my_turbo_streamer.replace(:object, partial: 'partial/name', locals: { object: object }
# .replace(:object2, partial: 'partial2/name2', locals: { object2: object2 }
#
# technical info... ChainableTagBuilder.each is called by the renderer
#
# Optimized 2: (Chained render syntax)
# -----------------------------------
# my_turbo_streamer
# .replace(:object, partial: 'partial/name', locals: { object: object }
# .replace(:object2, partial: 'partial2/name2', locals: { object2: object2 }
# .render
#
# Optimized 3: (Block Syntax)
# ----------------------------
# my_turbo_streamer do |s|
# s.replace(:object, partial: 'partial/name', locals: { object: object }
# s.replace(:object2, partial: 'partial2/name2', locals: { object2: object2 }
# end
#
module TurboStreamHelpersConcern
class ChainableTagBuilder < Turbo::Streams::TagBuilder
attr_reader :output
def initialize(controller, view_context, &block)
super(view_context)
@output = []
@controller = controller
replace(:flash, partial: 'shared/flash') if view_context.flash.present?
process_block(&block) if block
end
# Send an action of the type <tt>name</tt>. Options described in the concrete methods.
def action(*args, **kwargs, &block)
@output << super(*args, **kwargs, &block)
self
end
def each(&block)
output.each(&block)
end
def process_block(&block)
instance_eval(&block)
render
end
def render
@controller.render turbo_stream: self
end
end
def my_turbo_streamer(**options, &block)
flash.now[:alert] = options[:alert] if options.key?(:alert)
flash.now[:notice] = options[:notice] if options.key?(:notice)
TurboStreamHelpersConcern::ChainableTagBuilder.new(self, view_context, &block)
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment