joshleblanc / view_component_reflex

Call component methods right from your markup
http://view-component-reflex-expo.grep.sh/
MIT License
291 stars 27 forks source link

Reflex FormComponent::Base#handle_click failed: uninitialized constant FormComponent::BaseReflex #42

Closed cj closed 3 years ago

cj commented 3 years ago

I am trying a simple example

<%= component_controller do %>
  <%= reflex_tag :handle_click, :button, "Click Me", class: "button is-primary", type: "button" %>
<% end %>
# frozen_string_literal: true

module FormComponent
  class Base < ViewComponentReflex::Component
    def handle_click
      puts 'foo'
    end
  end
end

and I am getting the following error:

StimulusReflex::Channel#receive({"target"=>"FormComponent::Base#handle_click", "args"=>[], "url"=>"http://localhost:3000/", "attrs"=>{"class"=>"button is-primary", "type"=>"button", "data-reflex"=>"click->FormComponent::Base#handle_click", "data-key"=>"245b0f2cb6d05f6b57a2d86278f6b53be4852f2cb9bc38268789e960c1e35853", "data-controller"=>"stimulus-reflex", "data-action"=>"click->stimulus-reflex#__perform", "checked"=>false, "selected"=>false, "tag_name"=>"BUTTON", "value"=>""}, "dataset"=>{"data-reflex"=>"click->FormComponent::Base#handle_click", "data-key"=>"245b0f2cb6d05f6b57a2d86278f6b53be4852f2cb9bc38268789e960c1e35853", "data-controller"=>"stimulus-reflex", "data-action"=>"click->stimulus-reflex#__perform"}, "selectors"=>[], "reflexId"=>"0ac57349-ac26-4e60-9e9d-7b4d2c27e3e7", "resolveLate"=>false, "xpath"=>"/html/body/div[1]/div[1]/button[1]", "cXpath"=>"/html/body/div[1]/div[1]/button[1]", "reflexController"=>"stimulus-reflex", "permanentAttributeName"=>"data-reflex-permanent", "formData"=>""})
19:39:29 guard.1 | Reflex FormComponent::Base#handle_click failed: uninitialized constant FormComponent::BaseReflex
19:39:29 guard.1 | /Users/cj/.asdf/installs/ruby/2.7.2/lib/ruby/gems/2.7.0/gems/activesupport-6.1.0/lib/active_support/inflector/methods.rb:288:in `const_get' [http://localhost:3000/]

rails 6.1 gem 'stimulus_reflex', '~> 3.4.0.pre9' stimulus": "^2.0.0 stimulus_reflex": "3.4.0-pre8 gem 'view_component_reflex', '~> 3.0.0' gem 'view_component', '~> 2.23.1'

Let me know if you need any more information!

cj commented 3 years ago

I thought maybe removing https://github.com/joshleblanc/view_component_reflex/blob/master/lib/view_component_reflex/reflex_factory.rb#L18 would fix it, but the error still persists.

cj commented 3 years ago

Ok, so looks like it's a combination of:

@joshleblanc @hopsoft Is there a reason Reflex or Component is required in the name of a class?

joshleblanc commented 3 years ago

@cj view_component_reflex implicitly creates a reflex with the name Reflex. It's not created by the user, the libraries generates it on the fly. Given that, every reflex generated by view_component_reflex has Reflex at the end of its name.

VIewComponent's naming scheme has every component post-fixed by Component. Absolutely nothing makes the developer maintain this pattern, but view_component_reflex operates on the assumption that it's followed.

The monkey patch you linked in engine is used to initialize my generated reflex. When we receive a request to stimulate a component, we initialize the reflex.

Just looking at it, I could probably constantize anything being sent and checking if it responds to #init_stimulus_reflex instead of checking for the Component postfix

cj commented 3 years ago

@joshleblanc thank you for the response and that makes sense.

Would it be possible to just remove this check https://github.com/joshleblanc/view_component_reflex/blob/master/lib/view_component_reflex/engine.rb#L16 as ViewComponent's work without having Component appended to the end of a child class and it does not break anything for ViewComponentReflex?

I can submit a pull request if you like.

Cheers!

joshleblanc commented 3 years ago

Can't just only remove the check. That will throw incorrect warnings.

You'd have to constantize the component name, suppress any errors that throws, then check if it responds to init_stimulus_reflex, and run it if so. If the constantize succeeds, and it doesn't respond to init_stimulus_reflex, you could omit the current warning.

cj commented 3 years ago

Would something like this work?

            component = component.constantize

            if component.respond_to?(:init_stimulus_reflex)
              begin
                component.init_stimulus_reflex
              rescue StandardError
                p "Tried to initialize view_component_reflex on #{component_name}, but it's not a view_component_reflex"
              end

            end
joshleblanc commented 3 years ago

Something more like this


            component = begin
              component_name.constantize
            rescue
              # Since every reflex runs through this monkey patch, we're just going to ignore the ones that aren't for components
            end

            if component&.respond_to?(:init_stimulus_reflex)
              component.init_stimulus_reflex
            else
              p "Tried to initialize view_component_reflex on #{component_name}, but it's not a view_component_reflex"
            end
cj commented 3 years ago

That looks better.... (I had updated my comment because I made a mistake, I was writing it while eating lunch. lol)

cj commented 3 years ago

@joshleblanc If you'd like me to open a pull request let me know. Thank you again!

joshleblanc commented 3 years ago

Just testing it now