Skip to content

Conversation

@erikaxel
Copy link

Even though the best practice docs suggest not using inheritance, I hope you will consider this fix since it is a regression from 3.x

The steps to reproduce and fix was created with Claude after we found this issue in our project. I have manually checked the code and verified that it solves our issue.

Steps to reproduce

This error occurs when:

  1. A child component inherits from a parent component
  2. Both components have their own template files
  3. Template files are named without an explicit format (e.g., component.slim instead of component.html.slim)

Create parent component:

app/components/parent_component.rb:

# frozen_string_literal: true

class ParentComponent < ViewComponent::Base
  def message
    "Parent message"
  end
end

app/components/parent_component.slim (note: no .html in filename):

.parent
  p = message

Create child component that inherits from parent:

app/components/child_component.rb:

# frozen_string_literal: true

class ChildComponent < ParentComponent
  def initialize(name:)
    @name = name
  end

  def message
    "Hello, #{@name}!"
  end
end

app/components/child_component.slim (note: no .html in filename):

.child
  p = message
  p This is the child component

Render the component:

# In a controller or view
render ChildComponent.new(name: "World")

Expected behavior

The component should render successfully, using the child component's template and displaying "Hello, World!".

Actual behavior

The application raises a NoMethodError during component compilation:

NoMethodError:
  undefined method 'upcase' for nil

Root cause: When template files are named without an explicit format (e.g., component.slim instead of component.html.slim), the ActionView::Resolver::PathParser returns nil for the format. The template validation code at line 120 of compiler.rb attempts to call .upcase on this nil value.

Workaround: Rename template files to include explicit format:

mv app/components/parent_component.slim app/components/parent_component.html.slim
mv app/components/child_component.slim app/components/child_component.html.slim

Note: This worked without issues in ViewComponent 3.x. This appears to be a regression in the template validation logic introduced in ViewComponent 4.x.

Backtrace:

NoMethodError:
  undefined method 'upcase' for nil
# gems/view_component-4.1.0/lib/view_component/compiler.rb:120:in 'block in template_errors'

The error occurs at this line in compiler.rb:

errors << "More than one #{this_format.upcase} template found#{variant_string} for #{@component}. "

System configuration

Rails version: 8.0

Ruby version: 3.4

Gem version: 4.1.0

…ine render

Allows ViewComponent inheritance to work as it did in 3.x
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant