ViewComponent / view_component

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

undefined local variable or method `preview_source' #1654

Open olleolleolle opened 1 year ago

olleolleolle commented 1 year ago

The preview.erb.html rendered by the ViewComponent Previews uses a PreviewHelper method.

In my app, which has 1 preview, this method was not found.

Are you using the Source feature in Previews?

Steps to reproduce

I did this:

When rendering, I got the error described below.

Expected behavior

The component to render, and after it, a source code display with syntax highlighting.

Actual behavior

 Showing /home/olle/code/myapp/gems/gems/view_component-2.82.0/app/views/view_components/preview.html.erb where line #12 raised:

undefined local variable or method `preview_source' for #<ActionView::Base:0x00000000097c70>

Workaround: inlined the check for whether to render "preview_source" or not:

In using the latest version, I could see that it was doable except for finding the helper method - I inlined the check for @render_args which is perhaps an alright change to this very literal view file?

<% if ViewComponent::Base.config.show_previews_source %>
  <% unless @render_args.nil? %>
    <%= render "preview_source" %>
  <% end %>
<% end %>

I created in my application code, this file: app/views/view_components/preview.html.erb


<% # Line 13: The PreviewHelper seems not to be available, so we have inlined it. Workaround from https://github.com/ViewComponent/view_component/issues/1654 %>
<% if @render_args[:component] %>
  <% if ViewComponent::Base.config.render_monkey_patch_enabled || Rails.version.to_f >= 6.1 %>
    <%= render(@render_args[:component], @render_args[:args], &@render_args[:block]) %>
  <% else %>
    <%= render_component(@render_args[:component], &@render_args[:block]) %>
  <% end %>
<% else %>
  <%= render template: @render_args[:template], locals: @render_args[:locals] || {} %>
<% end %>

<% if ViewComponent::Base.config.show_previews_source %>
  <%# <%= preview_source %1> %>
  <% unless @render_args.nil? %>
    <%= render "preview_source" %>
  <% end %>
<% end %>

System configuration

Rails version: 6.1

Ruby version: 3.1.3

Gem version: 2.82.0

olleolleolle commented 1 year ago

When I added the workaround, I was able to see the source rendering. Practical feature!

bild

PS: The output of that ViewComponent is sort of... yes, just an empty DIV. That's the empty state, all good.

joelhawksley commented 1 year ago

@edwinthinks would you be able to look into this? I wonder if this was introduced with your test helper feature.

joelhawksley commented 1 year ago

@olleolleolle would you be willing to open a PR with a failing test case, or at least provide a stack trace here?

olleolleolle commented 1 year ago

Let's see what I can do tomorrow,

Cc @olleolleolle

olleolleolle commented 1 year ago

First, I removed the view file with the noted workaround, then I visited http://mybox/rails/view_components/admin/table_component/with_my_settings.

Error message:

Showing /home/olle/.devbox/code/myapp/gems/gems/view_component-2.82.0/app/views/view_components/preview.html.erb where line #12 raised:

undefined local variable or method `preview_source' for #<ActionView::Base:0x000000000d31a8>

Stack trace, the "Full" version from Rails' error page.

Stack trace here
view_component (2.82.0) app/views/view_components/preview.html.erb:12
actionview (7.0.4.3) lib/action_view/base.rb:244:in `public_send'
actionview (7.0.4.3) lib/action_view/base.rb:244:in `_run'
actionview (7.0.4.3) lib/action_view/template.rb:157:in `block in render'
activesupport (7.0.4.3) lib/active_support/notifications.rb:208:in `instrument'
actionview (7.0.4.3) lib/action_view/template.rb:361:in `instrument_render_template'
actionview (7.0.4.3) lib/action_view/template.rb:155:in `render'
actionview (7.0.4.3) lib/action_view/renderer/template_renderer.rb:65:in `block (2 levels) in render_template'
activesupport (7.0.4.3) lib/active_support/notifications.rb:206:in `block in instrument'
activesupport (7.0.4.3) lib/active_support/notifications/instrumenter.rb:24:in `instrument'
activesupport (7.0.4.3) lib/active_support/notifications.rb:206:in `instrument'
actionview (7.0.4.3) lib/action_view/renderer/template_renderer.rb:60:in `block in render_template'
actionview (7.0.4.3) lib/action_view/renderer/template_renderer.rb:75:in `block in render_with_layout'
activesupport (7.0.4.3) lib/active_support/notifications.rb:206:in `block in instrument'
activesupport (7.0.4.3) lib/active_support/notifications/instrumenter.rb:24:in `instrument'
activesupport (7.0.4.3) lib/active_support/notifications.rb:206:in `instrument'
actionview (7.0.4.3) lib/action_view/renderer/template_renderer.rb:74:in `render_with_layout'
actionview (7.0.4.3) lib/action_view/renderer/template_renderer.rb:59:in `render_template'
actionview (7.0.4.3) lib/action_view/renderer/template_renderer.rb:11:in `render'
actionview (7.0.4.3) lib/action_view/renderer/renderer.rb:61:in `render_template_to_object'
actionview (7.0.4.3) lib/action_view/renderer/renderer.rb:29:in `render_to_object'
actionview (7.0.4.3) lib/action_view/rendering.rb:117:in `block in _render_template'
actionview (7.0.4.3) lib/action_view/base.rb:270:in `in_rendering_context'
actionview (7.0.4.3) lib/action_view/rendering.rb:116:in `_render_template'
actionpack (7.0.4.3) lib/action_controller/metal/streaming.rb:216:in `_render_template'
actionview (7.0.4.3) lib/action_view/rendering.rb:103:in `render_to_body'
actionpack (7.0.4.3) lib/action_controller/metal/rendering.rb:46:in `render_to_body'
actionpack (7.0.4.3) lib/action_controller/metal/renderers.rb:141:in `render_to_body'
actionpack (7.0.4.3) lib/abstract_controller/rendering.rb:25:in `render'
actionpack (7.0.4.3) lib/action_controller/metal/rendering.rb:30:in `render'
actionpack (7.0.4.3) lib/action_controller/metal/instrumentation.rb:22:in `block (2 levels) in render'
/opt/devbox/dependencies/ruby-ruby-3.2.2-gems-3.4.3-bundler-2.4.10-wti-2.7.4/lib/ruby/3.2.0/benchmark.rb:311:in `realtime'
activesupport (7.0.4.3) lib/active_support/core_ext/benchmark.rb:14:in `ms'
actionpack (7.0.4.3) lib/action_controller/metal/instrumentation.rb:22:in `block in render'
actionpack (7.0.4.3) lib/action_controller/metal/instrumentation.rb:91:in `cleanup_view_runtime'
activerecord (7.0.4.3) lib/active_record/railties/controller_runtime.rb:34:in `cleanup_view_runtime'
actionpack (7.0.4.3) lib/action_controller/metal/instrumentation.rb:21:in `render'
wicked_pdf (2.6.3) lib/wicked_pdf/pdf_helper.rb:18:in `render'
view_component (2.82.0) app/controllers/concerns/view_component/preview_actions.rb:38:in `previews'
actionpack (7.0.4.3) lib/action_controller/metal/basic_implicit_render.rb:6:in `send_action'
actionpack (7.0.4.3) lib/abstract_controller/base.rb:215:in `process_action'
actionpack (7.0.4.3) lib/action_controller/metal/rendering.rb:53:in `process_action'
actionpack (7.0.4.3) lib/abstract_controller/callbacks.rb:234:in `block in process_action'
activesupport (7.0.4.3) lib/active_support/callbacks.rb:118:in `block in run_callbacks'
i18n (1.12.0) lib/i18n.rb:322:in `with_locale'
view_component (2.82.0) app/controllers/concerns/view_component/preview_actions.rb:68:in `set_locale'
activesupport (7.0.4.3) lib/active_support/callbacks.rb:127:in `block in run_callbacks'
activesupport (7.0.4.3) lib/active_support/callbacks.rb:138:in `run_callbacks'
actionpack (7.0.4.3) lib/abstract_controller/callbacks.rb:233:in `process_action'
actionpack (7.0.4.3) lib/action_controller/metal/rescue.rb:22:in `process_action'
actionpack (7.0.4.3) lib/action_controller/metal/instrumentation.rb:67:in `block in process_action'
activesupport (7.0.4.3) lib/active_support/notifications.rb:206:in `block in instrument'
activesupport (7.0.4.3) lib/active_support/notifications/instrumenter.rb:24:in `instrument'
activesupport (7.0.4.3) lib/active_support/notifications.rb:206:in `instrument'
actionpack (7.0.4.3) lib/action_controller/metal/instrumentation.rb:66:in `process_action'
actionpack (7.0.4.3) lib/action_controller/metal/params_wrapper.rb:259:in `process_action'
activerecord (7.0.4.3) lib/active_record/railties/controller_runtime.rb:27:in `process_action'
actionpack (7.0.4.3) lib/abstract_controller/base.rb:151:in `process'
actionview (7.0.4.3) lib/action_view/rendering.rb:39:in `process'
actionpack (7.0.4.3) lib/action_controller/metal.rb:188:in `dispatch'
actionpack (7.0.4.3) lib/action_controller/metal.rb:251:in `dispatch'
actionpack (7.0.4.3) lib/action_dispatch/routing/route_set.rb:49:in `dispatch'
actionpack (7.0.4.3) lib/action_dispatch/routing/route_set.rb:32:in `serve'
actionpack (7.0.4.3) lib/action_dispatch/journey/router.rb:50:in `block in serve'
actionpack (7.0.4.3) lib/action_dispatch/journey/router.rb:32:in `each'
actionpack (7.0.4.3) lib/action_dispatch/journey/router.rb:32:in `serve'
actionpack (7.0.4.3) lib/action_dispatch/routing/route_set.rb:852:in `call'
actionpack (7.0.4.3) lib/action_dispatch/middleware/static.rb:23:in `call'
omniauth (2.1.1) lib/omniauth/strategy.rb:202:in `call!'
omniauth (2.1.1) lib/omniauth/strategy.rb:169:in `call'
omniauth (2.1.1) lib/omniauth/builder.rb:44:in `call'
bullet (7.0.7) lib/bullet/rack.rb:14:in `call'
rack (2.2.6.4) lib/rack/tempfile_reaper.rb:15:in `call'
rack (2.2.6.4) lib/rack/etag.rb:27:in `call'
rack (2.2.6.4) lib/rack/conditional_get.rb:27:in `call'
rack (2.2.6.4) lib/rack/head.rb:12:in `call'
actionpack (7.0.4.3) lib/action_dispatch/http/permissions_policy.rb:38:in `call'
actionpack (7.0.4.3) lib/action_dispatch/http/content_security_policy.rb:36:in `call'
rack (2.2.6.4) lib/rack/session/abstract/id.rb:266:in `context'
rack (2.2.6.4) lib/rack/session/abstract/id.rb:260:in `call'
actionpack (7.0.4.3) lib/action_dispatch/middleware/cookies.rb:704:in `call'
app/middleware/report_details_to_developers_for_cookie_overflow_errors.rb:12:in `call'
activerecord (7.0.4.3) lib/active_record/migration.rb:603:in `call'
actionpack (7.0.4.3) lib/action_dispatch/middleware/callbacks.rb:27:in `block in call'
activesupport (7.0.4.3) lib/active_support/callbacks.rb:99:in `run_callbacks'
actionpack (7.0.4.3) lib/action_dispatch/middleware/callbacks.rb:26:in `call'
actionpack (7.0.4.3) lib/action_dispatch/middleware/executor.rb:14:in `call'
actionpack (7.0.4.3) lib/action_dispatch/middleware/actionable_exceptions.rb:17:in `call'
actionpack (7.0.4.3) lib/action_dispatch/middleware/debug_exceptions.rb:28:in `call'
actionpack (7.0.4.3) lib/action_dispatch/middleware/show_exceptions.rb:26:in `call'
railties (7.0.4.3) lib/rails/rack/logger.rb:40:in `call_app'
railties (7.0.4.3) lib/rails/rack/logger.rb:25:in `block in call'
activesupport (7.0.4.3) lib/active_support/tagged_logging.rb:99:in `block in tagged'
activesupport (7.0.4.3) lib/active_support/tagged_logging.rb:37:in `tagged'
activesupport (7.0.4.3) lib/active_support/tagged_logging.rb:99:in `tagged'
railties (7.0.4.3) lib/rails/rack/logger.rb:25:in `call'
sprockets-rails (3.4.2) lib/sprockets/rails/quiet_assets.rb:13:in `call'
actionpack (7.0.4.3) lib/action_dispatch/middleware/remote_ip.rb:93:in `call'
request_store (1.5.1) lib/request_store/middleware.rb:19:in `call'
rack-timeout (0.6.3) lib/rack/timeout/core.rb:148:in `block in call'
rack-timeout (0.6.3) lib/rack/timeout/support/timeout.rb:19:in `timeout'
rack-timeout (0.6.3) lib/rack/timeout/core.rb:147:in `call'
actionpack (7.0.4.3) lib/action_dispatch/middleware/request_id.rb:26:in `call'
rack (2.2.6.4) lib/rack/method_override.rb:24:in `call'
rack (2.2.6.4) lib/rack/runtime.rb:22:in `call'
activesupport (7.0.4.3) lib/active_support/cache/strategy/local_cache_middleware.rb:29:in `call'
app/middleware/bad_multipart_form_data_sanitizer.rb:21:in `call'
actionpack (7.0.4.3) lib/action_dispatch/middleware/server_timing.rb:61:in `block in call'
actionpack (7.0.4.3) lib/action_dispatch/middleware/server_timing.rb:26:in `collect_events'
actionpack (7.0.4.3) lib/action_dispatch/middleware/server_timing.rb:60:in `call'
actionpack (7.0.4.3) lib/action_dispatch/middleware/executor.rb:14:in `call'
actionpack (7.0.4.3) lib/action_dispatch/middleware/static.rb:23:in `call'
rack (2.2.6.4) lib/rack/sendfile.rb:110:in `call'
actionpack (7.0.4.3) lib/action_dispatch/middleware/host_authorization.rb:137:in `call'
app/middleware/cloudflare_middleware.rb:14:in `call'
rack-utf8_sanitizer (1.8.0) lib/rack/utf8_sanitizer.rb:28:in `call'
app/middleware/faster_assets_in_development.rb:24:in `call'
app/middleware/remove_trailing_slashes.rb:26:in `call'
honeybadger (5.2.1) lib/honeybadger/rack/error_notifier.rb:33:in `block in call'
honeybadger (5.2.1) lib/honeybadger/agent.rb:433:in `with_rack_env'
honeybadger (5.2.1) lib/honeybadger/rack/error_notifier.rb:30:in `call'
honeybadger (5.2.1) lib/honeybadger/rack/user_feedback.rb:31:in `call'
honeybadger (5.2.1) lib/honeybadger/rack/user_informer.rb:21:in `call'
hirefire-resource (0.10.1) lib/hirefire/middleware.rb:37:in `call'
rack-mini-profiler (3.1.0) lib/mini_profiler.rb:413:in `call'
webpacker (5.4.4) lib/webpacker/dev_server_proxy.rb:25:in `perform_request'
rack-proxy (0.7.6) lib/rack/proxy.rb:87:in `call'
railties (7.0.4.3) lib/rails/engine.rb:530:in `call'
puma (6.2.1) lib/puma/configuration.rb:270:in `call'
puma (6.2.1) lib/puma/request.rb:98:in `block in handle_request'
puma (6.2.1) lib/puma/thread_pool.rb:340:in `with_force_shutdown'
puma (6.2.1) lib/puma/request.rb:97:in `handle_request'
puma (6.2.1) lib/puma/server.rb:431:in `process_client'
puma (6.2.1) lib/puma/server.rb:233:in `block in run'
puma (6.2.1) lib/puma/thread_pool.rb:147:in `block in spawn_thread' 
joelhawksley commented 1 year ago

@olleolleolle thanks for sharing a stack trace! I think it would be helpful to have a PR for a failing test for this bug. Would you be willing to get one started?

reeganviljoen commented 1 year ago

@donapieppo do you know if the change you added to 3.1 has fixed this issue

donapieppo commented 1 year ago

I could not reproduce the original issue. With Rails 6.0 and view_component-3.0.0 rendering the preview (/rails/view_components/admin/attributes_table_component/with_an_empty_list) worked fine for me.

reeganviljoen commented 1 year ago

@olleolleolle can you confirm if this issue is still present with view_component 3.1

olleolleolle commented 1 year ago

@reeganviljoen I have the same issue after updating to 3.1.0. Sorry not to have a neat repro, it's a little hectic right now.

reeganviljoen commented 1 year ago

@olleolleolle it's all cool, I will see if I can help out at some point

reeganviljoen commented 11 months ago

@olleolleolle @donapieppo I have manged to reproduce the issue in #1899 it seems to happen when their are no params present in the preview url

reeganviljoen commented 11 months ago

False alarm I made an error where I ommited the = in the erb

triskweline commented 3 months ago

The cause of this error is that previews are rendered via ViewComponentsController by default, and that controller does not include the PreviewHelper that defines preview_source.

A workaround for me is to define a custom controller that does include the helper:

# config/application.rb

config.view_component.show_previews_source = true
config.view_component.preview_controller = "ComponentPreviewController"

# app/controllers/component_preview_controller.rb
class Test::ComponentPreviewController < ViewComponentsController
  helper :preview
end
reeganviljoen commented 3 months ago

@triskweline since you have made this fix locally would you like to fix this in the source, otherwise I wouldn't mind

triskweline commented 3 months ago

The cause of this error is that previews are rendered via ViewComponentsController by default, and that controller does not include the PreviewHelper that defines preview_source.

A little more background: You only need a custom controller if you have configured Rails to not include all helpers by default:

# config/application.rb
config.action_controller.include_all_helpers = false

If you delete that line (or set the config to true), you won't need a custom controller.

That config has been defaulting to true for a while. I believe the people who are experiencing this issue have disabled this config, either by default, or by inheriting an old setting when upgrading Rails.

Some projects won't be able to enable this setting because they need different sets of helpers for different controllers.

triskweline commented 3 months ago

@triskweline since you have made this fix locally would you like to fix this in the source, otherwise I wouldn't mind

I would appreciate your help. I actually set up the repo, but didn't immediately see where to add a test.

I think a solution could be to add a helper PreviewHelper to ViewComponentsController. This way source previews would work out of the box, with whatever setting of config.action_controller.include_all_helpers.

joelhawksley commented 3 months ago

@triskweline that sounds good to me. I think this will be tricky to test so I'm OK going without one in this case.