Class: StimulusReflex::Reflex

Inherits:
Object
  • Object
show all
Includes:
ActionView::Helpers::TagHelper, ActiveSupport::Rescuable, CableReady::Identifiable, CableReadiness, Callbacks, VersionChecker
Defined in:
lib/stimulus_reflex/reflex.rb

Instance Attribute Summary collapse

Attributes included from CableReadiness

#cable_ready

Instance Method Summary collapse

Methods included from VersionChecker

#check_version!

Constructor Details

#initialize(channel, reflex_data:) ⇒ Reflex

Returns a new instance of Reflex.



28
29
30
31
32
33
34
35
36
# File 'lib/stimulus_reflex/reflex.rb', line 28

def initialize(channel, reflex_data:)
  @channel = channel
  @reflex_data = reflex_data
  @broadcaster = StimulusReflex::PageBroadcaster.new(self)
  @payload = {}
  @headers = {}

  check_version!
end

Instance Attribute Details

#broadcasterObject (readonly)

Returns the value of attribute broadcaster.



15
16
17
# File 'lib/stimulus_reflex/reflex.rb', line 15

def broadcaster
  @broadcaster
end

#channelObject (readonly)

Returns the value of attribute channel.



15
16
17
# File 'lib/stimulus_reflex/reflex.rb', line 15

def channel
  @channel
end

#headersObject

Returns the value of attribute headers.



14
15
16
# File 'lib/stimulus_reflex/reflex.rb', line 14

def headers
  @headers
end

#payloadObject

Returns the value of attribute payload.



14
15
16
# File 'lib/stimulus_reflex/reflex.rb', line 14

def payload
  @payload
end

#reflex_dataObject (readonly) Also known as: data

Returns the value of attribute reflex_data.



15
16
17
# File 'lib/stimulus_reflex/reflex.rb', line 15

def reflex_data
  @reflex_data
end

Instance Method Details

#controllerObject



100
101
102
103
104
105
106
107
108
109
110
# File 'lib/stimulus_reflex/reflex.rb', line 100

def controller
  @controller ||= controller_class.new.tap do |c|
    request.headers.merge!(headers)
    c.instance_variable_set :@stimulus_reflex, true
    c.set_request! request
    c.set_response! controller_class.make_response!(request)
  end

  instance_variables.each { |name| @controller.instance_variable_set name, instance_variable_get(name) }
  @controller
end

#controller?Boolean

Returns:

  • (Boolean)


112
113
114
# File 'lib/stimulus_reflex/reflex.rb', line 112

def controller?
  !!defined? @controller
end

#default_reflexObject



140
141
142
# File 'lib/stimulus_reflex/reflex.rb', line 140

def default_reflex
  # noop default reflex to force page reloads
end

#forbidden?Boolean

Indicates if the callback chain was halted via a throw(:forbidden) in a before_reflex callback.

Returns:

  • (Boolean)


136
137
138
# File 'lib/stimulus_reflex/reflex.rb', line 136

def forbidden?
  !!@forbidden
end

#halted?Boolean

Indicates if the callback chain was halted via a throw(:abort) in a before_reflex callback. SEE: https://api.rubyonrails.org/classes/ActiveSupport/Callbacks.html IMPORTANT: The reflex will not re-render the page if the callback chain is halted

Returns:

  • (Boolean)


131
132
133
# File 'lib/stimulus_reflex/reflex.rb', line 131

def halted?
  !!@halted
end

#loggerObject

END TODO: remove



45
46
47
# File 'lib/stimulus_reflex/reflex.rb', line 45

def logger
  @logger ||= StimulusReflex::Logger.new(self) unless suppress_logging
end

#morph(selectors, html = nil) ⇒ Object



86
87
88
89
90
91
92
93
94
95
96
97
98
# File 'lib/stimulus_reflex/reflex.rb', line 86

def morph(selectors, html = nil)
  case selectors
  when :page
    raise StandardError.new("Cannot call :page morph after :#{broadcaster.to_sym} morph") unless broadcaster.page?
  when :nothing
    raise StandardError.new("#{broadcaster.to_sym} morph type has already been set") if broadcaster.selector?
    @broadcaster = StimulusReflex::NothingBroadcaster.new(self) unless broadcaster.nothing?
  else
    raise StandardError.new("#{broadcaster.to_sym} morph type has already been set") if broadcaster.nothing?
    @broadcaster = StimulusReflex::SelectorBroadcaster.new(self) unless broadcaster.selector?
    broadcaster.append_morph(selectors, html)
  end
end

#paramsObject



144
145
146
# File 'lib/stimulus_reflex/reflex.rb', line 144

def params
  @_params ||= ActionController::Parameters.new(request.parameters)
end

#process(name, *args) ⇒ Object

Invoke the reflex action specified by name and run all callbacks



124
125
126
# File 'lib/stimulus_reflex/reflex.rb', line 124

def process(name, *args)
  run_callbacks(:process) { public_send(name, *args) }
end

#reflex_idObject

TODO: remove this for v4



39
40
41
42
# File 'lib/stimulus_reflex/reflex.rb', line 39

def reflex_id
  warn "Deprecation warning: reflex_id will be removed in v4. Use id instead!" if Rails.env.development?
  id
end

#render(*args) ⇒ Object



116
117
118
119
120
121
# File 'lib/stimulus_reflex/reflex.rb', line 116

def render(*args)
  options = args.extract_options!
  (options[:locals] ||= {}).reverse_merge!(params: params)
  args << options.reverse_merge(layout: false)
  controller_class.renderer.new(connection.env.merge("SCRIPT_NAME" => "")).render(*args)
end

#render_collection(resource, content = nil) ⇒ Object

morphdom needs content to be wrapped in an element with the same id when children_only: true Oddly, it doesn't matter if the target element is a div! See: https://docs.stimulusreflex.com/appendices/troubleshooting#different-element-type-altogether-who-cares-so-long-as-the-css-selector-matches Used internally to allow automatic partial collection rendering, but also useful to library users eg. morph dom_id(@posts), render_collection(@posts)



152
153
154
155
# File 'lib/stimulus_reflex/reflex.rb', line 152

def render_collection(resource, content = nil)
  content ||= render(resource)
  tag.div(content.html_safe, id: dom_id(resource).from(1))
end

#requestObject



49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
# File 'lib/stimulus_reflex/reflex.rb', line 49

def request
  @request ||= begin
    uri = URI.parse(url)
    path = ActionDispatch::Journey::Router::Utils.normalize_path(uri.path)
    query_hash = Rack::Utils.parse_nested_query(uri.query)
    mock_env = Rack::MockRequest.env_for(uri.to_s)

    mock_env.merge!(
      "rack.request.query_hash" => query_hash,
      "rack.request.query_string" => uri.query,
      "ORIGINAL_SCRIPT_NAME" => "",
      "ORIGINAL_FULLPATH" => path,
      Rack::SCRIPT_NAME => "",
      Rack::PATH_INFO => path,
      Rack::REQUEST_PATH => path,
      Rack::QUERY_STRING => uri.query
    )

    env = connection.env.merge(mock_env)

    middleware = StimulusReflex.config.middleware

    if middleware.any?
      stack = middleware.build(Rails.application.routes)
      stack.call(env)
    end

    req = ActionDispatch::Request.new(env)

    # fetch path params (controller, action, ...) and apply them
    request_params = StimulusReflex::RequestParameters.new(params: reflex_data.params, req: req, url: url)
    req = request_params.apply!

    req
  end
end