ViewComponent / view_component

A framework for building reusable, testable & encapsulated view components in Ruby on Rails.
https://viewcomponent.org
MIT License
3.32k stars 440 forks source link

Template file and inline render method found for ComponentName #2114

Closed Paul-Bob closed 1 month ago

Paul-Bob commented 1 month ago

Starting with view_component version 3.15.0 and above, some Avo users start to notice some error raised by ViewComponent.

I'm not sure how to reproduce the error, since on my local environment sometimes happens and sometimes not. Same steps on other local environment don't even trigger the error.

I created this issue on Avo and @rickychilcott confirmed that already noticed this error on some parts of the application unrelated to Avo, so I guess it might be a ViewComponent issue.

I wish I could provide more details, but this is all the information I have gathered so far.

Error:

image

rickychilcott commented 1 month ago

The issue is intermittent for me, and I have only noticed it in development. I believe it occurs when the app is reloaded. Last night, while working on a ViewComponent and refreshing my app, it would happen, and then triggering a few reloads would eventually resolve it.

So I think it has to do with code reloading, if I had to guess.

adrianthedev commented 1 month ago

I can't replicate it on my machine. Without pointing any fingers, I have a hunch it's not particularly Avo, but something in the new VC release.

joelhawksley commented 1 month ago

Thanks for the report @Paul-Bob! I refactored the ViewComponent compiler in v3.15.0 without changing the public API or test suite, but this kind of failure mode is notoriously difficult to test for.

If you can, can you update to v3.16.0 that includes more debug information with template errors? That should give us more information on what's going on with the hope that we can write a test case that reproduces this bug ❤

Paul-Bob commented 1 month ago

Hey @joelhawksley thank you for the prompt help!

Does this ring any bell?

web    | ActionView::Template::Error (Template file and inline render method found for Avo::Cards::CardComponent. There can only be a template file or inline render method per component.
web    | Template file and inline render method found for variant '' in Avo::Cards::CardComponent. There can only be a template file or inline render method per variant.
web    | Templates:
web    | #<ViewComponent::Template:0x000072664b2633f0 @component=Avo::Cards::CardComponent, @type=:file, @this_format=:html, @variant=nil, @lineno=0, @path="/home/bob/.rbenv/versions/3.3.0/lib/ruby/gems/3.3.0/gems/avo-dashboards-3.13.0/app/components/avo/cards/card_component.html.erb", @extension="erb", @source=nil, @method_name=nil, @defined_on_self=true, @source_originally_nil=true, @call_method_name="call">
web    | #<ViewComponent::Template:0x000072664b262db0 @component=Avo::Cards::CardComponent, @type=:inline_call, @this_format=:html, @variant=nil, @lineno=nil, @path=nil, @extension=nil, @source=nil, @method_name=:call, @defined_on_self=true, @source_originally_nil=true, @call_method_name=:call>):
web    | 
web    | Causes:
web    | ViewComponent::TemplateError (Template file and inline render method found for Avo::Cards::CardComponent. There can only be a template file or inline render method per component.
web    | Template file and inline render method found for variant '' in Avo::Cards::CardComponent. There can only be a template file or inline render method per variant.
web    | Templates:
web    | #<ViewComponent::Template:0x000072664b2633f0 @component=Avo::Cards::CardComponent, @type=:file, @this_format=:html, @variant=nil, @lineno=0, @path="/home/bob/.rbenv/versions/3.3.0/lib/ruby/gems/3.3.0/gems/avo-dashboards-3.13.0/app/components/avo/cards/card_component.html.erb", @extension="erb", @source=nil, @method_name=nil, @defined_on_self=true, @source_originally_nil=true, @call_method_name="call">
web    | #<ViewComponent::Template:0x000072664b262db0 @component=Avo::Cards::CardComponent, @type=:inline_call, @this_format=:html, @variant=nil, @lineno=nil, @path=nil, @extension=nil, @source=nil, @method_name=:call, @defined_on_self=true, @source_originally_nil=true, @call_method_name=:call>)
web    |     1: <%= render Avo::TurboFrameWrapperComponent.new(params[:turbo_frame]) do %>
web    |     2:   <%= render Avo::Cards::CardComponent.new card: @card %>
web    |     3: <% end %>
web    |   
web    | lib/middleware/account_middleware.rb:32:in `call'
adrianthedev commented 1 month ago

The CardComponent does not have an inline render method, but uses a template.

# frozen_string_literal: true

class Avo::Cards::CardComponent < ViewComponent::Base
  attr_reader :card

  def initialize(card: nil)
    @card = card

    init_card
  end

  def render?
    card.present?
  end

  def init_card
    card.query if card.respond_to? :query
  end
end
benoittgt commented 1 month ago

Hello 👋

With the updated version

Template file and inline render method found for AwxJobOrEventStatusComponent. There can only be a template file or inline render method per component. (ActionView::Template::Error)
Template file and inline render method found for variant '' in AwxJobOrEventStatusComponent. There can only be a template file or inline render method per variant.
Templates:
#<ViewComponent::Template:0x00007f247fece258 @component=AwxJobOrEventStatusComponent, @type=:file, @this_format=:html, @variant=nil, @lineno=0, @path="/home/appuser/app/components/awx_job_or_event_status_component.html.erb", @extension="erb", @source=nil, @method_name=nil, @defined_on_self=true, @source_originally_nil=true, @call_method_name="call">
#<ViewComponent::Template:0x00007f247fecdcb8 @component=AwxJobOrEventStatusComponent, @type=:inline_call, @this_format=:html, @variant=nil, @lineno=nil, @path=nil, @extension=nil, @source=nil, @method_name=:call, @defined_on_self=true, @source_originally_nil=true, @call_method_name=:call>

The component

# frozen_string_literal: true

class AwxJobOrEventStatusComponent < ApplicationComponent # ApplicationComponent has only one helper method

  include Rails.application.routes.url_helpers

  attr_reader :awx_job_or_event

  def initialize(awx_job_or_event:)
    @awx_job_or_event = awx_job_or_event
  end

  def color
    cross = {
      'canceled' => 'gray-600',
      'successful' => 'green-600',
      'pending' => 'gray-600',
      'error' => 'red-600',
      'failed' => 'red-600',
      'running' => 'orange-400',
    }
    cross.fetch(awx_job_or_event.status, cross['canceled'])
  end

end

The caller

<%= render(AwxJobOrEventStatusComponent.new(awx_job_or_event:)) %>
andrerpbts commented 1 month ago

I'm facing the same issue with some components in my application despite not using Avo on this one. It's intermittent, and after some reloads, it works again. I had to downgrade to 3.14 and lock this version until I get some clarification on how to solve it.

joelhawksley commented 1 month ago

👋🏻 I've yet to be able to reproduce this issue in dev or test environments. Are any of y'all's apps open source by chance? I'd also be interested in pairing to debug this issue if anyone is up for it ❤

Another option: @Paul-Bob do you have any desire to put together a test app that demonstrates this issue?

adrianthedev commented 1 month ago

Yes @Paul-Bob. I think a test app would be great.

Also, heads up @joelhawksley. This is also an issue that is somehow environment-dependent. Paul set up https://github.com/avo-hq/avo with this scenario, he could see the errors, but I wasn't able to reproduce them. And he wasn't the only one. We've had customers report this in local and production environments (so it's not just Paul's).

BlakeWilliams commented 1 month ago

👋 Hey y'all, I took a peek at the issue and I was able to reliably reproduce this.

It might not be the final version of the PR we end up merging since there's a few other difference in the compiler behavior to talk through and make decisions about, but I believe https://github.com/ViewComponent/view_component/pull/2121 should solve the issue y'all are running into here. If you don't mind pulling that branch and validating you no longer run into the issue that would be very helpful.

adrianthedev commented 1 month ago

@BlakeWilliams, you are the man 🙌 Thank you for looking into this. Paul will check as he is the one that can replicate it.

Paul-Bob commented 1 month ago

Hey @BlakeWilliams thank you for looking into this!

If you don't mind pulling that branch and validating you no longer run into the issue that would be very helpful.

I’ve tested using gem "view_component", git: "https://github.com/ViewComponent/view_component.git", branch: "bmw/fix-duplicate-template-error", and the issue seems to be resolved on my end. #2121 seems to have fixed it!

joelhawksley commented 1 month ago

Closed by https://github.com/ViewComponent/view_component/pull/2121