Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions docs/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ nav_order: 5

*Reegan Viljoen*

* Add `from:` option to `use_helpers` to allow for more flexible helper inclusion from modules.

*Reegan Viljoen*

## 3.12.1

* Ensure content is rendered correctly for forwarded slots.
Expand Down
12 changes: 12 additions & 0 deletions docs/guide/helpers.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,18 @@ class UseHelpersComponent < ViewComponent::Base
end
```

Methods defined in helper modules that are not available in the component can be included individually using the `from:` keyword:

```ruby
class UserComponent < ViewComponent::Base
use_helpers :icon, from: IconHelper
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess it would make sense to support the singular form use_helper as well?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Spone I have added this recommendation, as it seems like a great fit


def profile_icon
icon :user
end
end
```

## Nested URL helpers

Rails nested URL helpers implicitly depend on the current `request` in certain cases. Since ViewComponent is built to enable reusing components in different contexts, nested URL helpers should be passed their options explicitly:
Expand Down
22 changes: 21 additions & 1 deletion lib/view_component/use_helpers.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,35 @@ module ViewComponent::UseHelpers
extend ActiveSupport::Concern

class_methods do
def use_helpers(*args)
def use_helpers(*args, from: nil)
if from.nil?
define_helpers_without_source(*args)
else
define_helpers_with_source(*args, source: from)
end
end

private

def define_helpers_without_source(*args)
args.each do |helper_method|
class_eval(<<-RUBY, __FILE__, __LINE__ + 1)
def #{helper_method}(*args, &block)
raise HelpersCalledBeforeRenderError if view_context.nil?
__vc_original_view_context.#{helper_method}(*args, &block)
end
RUBY
ruby2_keywords(helper_method) if respond_to?(:ruby2_keywords, true)
end
end

def define_helpers_with_source(*args, source:)
args.each do |helper_method|
class_eval(<<-RUBY, __FILE__, __LINE__ + 1)
def #{helper_method}(*args, &block)
#{source}.instance_method(:#{helper_method}).bind(self).call(*args, &block)
end
RUBY
ruby2_keywords(helper_method) if respond_to?(:ruby2_keywords, true)
end
end
Expand Down
11 changes: 11 additions & 0 deletions test/sandbox/app/components/use_helpers_macro_component.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<div class='helper__message'>
<%= message %>
</div>

<div class='helper__args-message'>
<%= message_with_args('macro helper method') %>
</div>

<div class='helper__kwargs-message'>
<%= message_with_kwargs(name: 'macro kwargs helper method') %>
</div>
5 changes: 5 additions & 0 deletions test/sandbox/app/components/use_helpers_macro_component.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# frozen_string_literal: true

class UseHelpersMacroComponent < ViewComponent::Base
use_helpers :message, :message_with_args, :message_with_kwargs, from: MacroHelper
end
15 changes: 15 additions & 0 deletions test/sandbox/app/helpers/macro_helper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# frozen_string_literal: true

module MacroHelper
def message
"Hello helper method"
end

def message_with_args(name)
"Hello #{name}"
end

def message_with_kwargs(name:)
"Hello #{name}"
end
end
18 changes: 18 additions & 0 deletions test/sandbox/test/rendering_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1121,4 +1121,22 @@ def test_inline_component_renders_without_trailing_whitespace

refute @rendered_content =~ /\s+\z/, "Rendered component contains trailing whitespace"
end

def test_use_helper_macros
render_inline(UseHelpersMacroComponent.new)

assert_selector ".helper__message", text: "Hello helper method"
end

def test_use_helper_macros_with_args
render_inline(UseHelpersMacroComponent.new)

assert_selector ".helper__args-message", text: "Hello macro helper method"
end

def test_use_helper_macros_with_kwargs
render_inline(UseHelpersMacroComponent.new)

assert_selector ".helper__kwargs-message", text: "Hello macro kwargs helper method"
end
end