diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md
index ffd121035..d110e73b7 100644
--- a/docs/CHANGELOG.md
+++ b/docs/CHANGELOG.md
@@ -10,6 +10,10 @@ nav_order: 5
## main
+* Raise the error `RedefinedExistingMethodError` when declaring a slot which conflicts with an existing method.
+
+ *Hugo Chantelauze*
+
* Resolve an issue where slots starting with `call` would cause a `NameError`
*Blake Williams*
diff --git a/docs/index.md b/docs/index.md
index b20009efd..0ba8e83e2 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -141,6 +141,7 @@ ViewComponent is built by over a hundred members of the community, including:
+
diff --git a/lib/view_component/errors.rb b/lib/view_component/errors.rb
index b896f53d1..c2279ef8f 100644
--- a/lib/view_component/errors.rb
+++ b/lib/view_component/errors.rb
@@ -129,6 +129,16 @@ def initialize(klass_name, slot_name)
end
end
+ class RedefinedExistingMethodError < InvalidSlotNameError
+ MESSAGE =
+ "COMPONENT declares a slot named SLOT_NAME, which conflicts with an existing method.\n\n" \
+ "To fix this issue, choose a different slot name."
+
+ def initialize(klass_name, slot_name)
+ super(MESSAGE.gsub("COMPONENT", klass_name.to_s).gsub("SLOT_NAME", slot_name.to_s))
+ end
+ end
+
class ReservedSingularSlotNameError < InvalidSlotNameError
MESSAGE =
"COMPONENT declares a slot named SLOT_NAME, which is a reserved word in the ViewComponent framework.\n\n" \
diff --git a/lib/view_component/slotable.rb b/lib/view_component/slotable.rb
index d46094b3c..e3b1cd2ea 100644
--- a/lib/view_component/slotable.rb
+++ b/lib/view_component/slotable.rb
@@ -312,6 +312,11 @@ def validate_singular_slot_name(slot_name)
raise_if_slot_conflicts_with_call(slot_name)
raise_if_slot_ends_with_question_mark(slot_name)
raise_if_slot_registered(slot_name)
+ raise_if_method_exists(slot_name)
+ end
+
+ def raise_if_slot_ends_with_question_mark(slot_name)
+ raise SlotPredicateNameError.new(name, slot_name) if slot_name.to_s.ends_with?("?")
end
def raise_if_slot_registered(slot_name)
@@ -321,8 +326,10 @@ def raise_if_slot_registered(slot_name)
end
end
- def raise_if_slot_ends_with_question_mark(slot_name)
- raise SlotPredicateNameError.new(name, slot_name) if slot_name.to_s.ends_with?("?")
+ def raise_if_method_exists(slot_name)
+ if instance_methods.include?(slot_name)
+ raise RedefinedExistingMethodError.new(name, slot_name)
+ end
end
def raise_if_slot_conflicts_with_call(slot_name)
diff --git a/test/sandbox/test/slotable_test.rb b/test/sandbox/test/slotable_test.rb
index 086f418e5..8938bf8d0 100644
--- a/test/sandbox/test/slotable_test.rb
+++ b/test/sandbox/test/slotable_test.rb
@@ -741,4 +741,24 @@ def test_slot_names_can_start_with_call
end
end
end
+
+ def test_raises_error_on_slot_name_conflicting_with_existing_method_for_renders_one
+ exception = assert_raises ViewComponent::RedefinedExistingMethodError do
+ Class.new(ViewComponent::Base) do
+ renders_one :tag
+ end
+ end
+
+ assert_includes exception.message, "declares a slot named tag"
+ end
+
+ def test_raises_error_on_slot_name_conflicting_with_existing_method_for_renders_many
+ exception = assert_raises ViewComponent::RedefinedExistingMethodError do
+ Class.new(ViewComponent::Base) do
+ renders_many :tags
+ end
+ end
+
+ assert_includes exception.message, "declares a slot named tag"
+ end
end