From f9be01afb35078fca36c85b3951ef41acc6ebd84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zen=C3=A9ixe?= <1379179+Zeneixe@users.noreply.github.com> Date: Fri, 3 Nov 2023 18:53:28 +0100 Subject: [PATCH 1/8] Search for the Rails module in the root namespace (#1894) --- docs/CHANGELOG.md | 4 ++++ lib/view_component/base.rb | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 4af977c041..c9b233a5e0 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -10,6 +10,10 @@ nav_order: 5 ## main +* Fix bug where the `Rails` module wasn't being searched from the root namespace. + + *Zenéixe* + * Fix bug where `#with_request_url`, set the incorrect `request.fullpath`. *Nachiket Pusalkar* diff --git a/lib/view_component/base.rb b/lib/view_component/base.rb index 0bdee95af1..f5a91ac117 100644 --- a/lib/view_component/base.rb +++ b/lib/view_component/base.rb @@ -219,7 +219,7 @@ def helpers @__vc_helpers ||= __vc_original_view_context || controller.view_context end - if Rails.env.development? || Rails.env.test? + if ::Rails.env.development? || ::Rails.env.test? def method_missing(method_name, *args) # rubocop:disable Style/MissingRespondToMissing super rescue => e # rubocop:disable Style/RescueStandardError From 2bc5763a39c67e0d7da335cfa4ee403afa363d75 Mon Sep 17 00:00:00 2001 From: Reegan Viljoen <62689748+reeganviljoen@users.noreply.github.com> Date: Fri, 3 Nov 2023 20:25:12 +0200 Subject: [PATCH 2/8] Add new helper API (#1860) --- docs/CHANGELOG.md | 4 ++++ docs/guide/helpers.md | 20 +++++++++++++++++++ lib/view_component/base.rb | 1 + lib/view_component/use_helpers.rb | 20 +++++++++++++++++++ .../components/use_helpers_component.html.erb | 3 +++ .../app/components/use_helpers_component.rb | 7 +++++++ test/sandbox/test/rendering_test.rb | 5 +++++ 7 files changed, 60 insertions(+) create mode 100644 lib/view_component/use_helpers.rb create mode 100644 test/sandbox/app/components/use_helpers_component.html.erb create mode 100644 test/sandbox/app/components/use_helpers_component.rb diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index c9b233a5e0..9ab9a22967 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -10,6 +10,10 @@ nav_order: 5 ## main +* Add `use_helper` API. + + *Reegan Viljoen* + * Fix bug where the `Rails` module wasn't being searched from the root namespace. *Zenéixe* diff --git a/docs/guide/helpers.md b/docs/guide/helpers.md index 1407fe14a8..172c3aea08 100644 --- a/docs/guide/helpers.md +++ b/docs/guide/helpers.md @@ -51,6 +51,26 @@ class UserComponent < ViewComponent::Base end ``` +## UseHelpers setter + +By default, ViewComponents don't have access to helper methods defined externally. The `use_helpers` method allows external helpers to be called from the component. + +To use the `use_helpers` method, include `ViewComponent::UseHelpers`. +`UseHelpers` defines the helper on the component and is similar in use to using `delegate` on helpers. + +```ruby +class UseHelpersComponent < ViewComponent::Base + include ViewComponent::UseHelpers + use_helpers :icon + + erb_template <<-ERB +
+ <%= icon :user %> +
+ ERB +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: diff --git a/lib/view_component/base.rb b/lib/view_component/base.rb index f5a91ac117..6a2538c422 100644 --- a/lib/view_component/base.rb +++ b/lib/view_component/base.rb @@ -12,6 +12,7 @@ require "view_component/slotable" require "view_component/translatable" require "view_component/with_content_helper" +require "view_component/use_helpers" module ViewComponent class Base < ActionView::Base diff --git a/lib/view_component/use_helpers.rb b/lib/view_component/use_helpers.rb new file mode 100644 index 0000000000..32d13cd433 --- /dev/null +++ b/lib/view_component/use_helpers.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true + +module ViewComponent::UseHelpers + extend ActiveSupport::Concern + + class_methods do + def use_helpers(*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 + end +end diff --git a/test/sandbox/app/components/use_helpers_component.html.erb b/test/sandbox/app/components/use_helpers_component.html.erb new file mode 100644 index 0000000000..f24542007a --- /dev/null +++ b/test/sandbox/app/components/use_helpers_component.html.erb @@ -0,0 +1,3 @@ +
+ <%= message %> +
diff --git a/test/sandbox/app/components/use_helpers_component.rb b/test/sandbox/app/components/use_helpers_component.rb new file mode 100644 index 0000000000..375c07db63 --- /dev/null +++ b/test/sandbox/app/components/use_helpers_component.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +class UseHelpersComponent < ViewComponent::Base + include ViewComponent::UseHelpers + + use_helpers :message +end diff --git a/test/sandbox/test/rendering_test.rb b/test/sandbox/test/rendering_test.rb index 2f5069ea45..cd985beb66 100644 --- a/test/sandbox/test/rendering_test.rb +++ b/test/sandbox/test/rendering_test.rb @@ -1094,4 +1094,9 @@ def test_content_security_policy_nonce assert_selector("script", text: "\n//\n", visible: :hidden) end + + def test_use_helper + render_inline(UseHelpersComponent.new) + assert_selector ".helper__message", text: "Hello helper method" + end end From ad27702b38d5d4d5f5752ca64d1e7ce389677406 Mon Sep 17 00:00:00 2001 From: Blake Williams Date: Fri, 3 Nov 2023 14:42:29 -0400 Subject: [PATCH 3/8] Fix slot names that start with call (#1828) * Fix slot names that start with call When a component is registered that starts with `call` the compiler detects it as a template method which is not correct. This changes the compiler to look for `call(_|$)` instead of `call` to avoid this issue. This means that slots can't (and couldn't) start with `call_` since we still rely on the `call_` naming convention to generate the template methods. To make this more dev friendly, this adds a check that raises an error if a slot name starts with `call_`. A more long-term fix would be to use some kind of template method container instead of relying on the `call_` naming convention. --- docs/CHANGELOG.md | 4 ++++ lib/view_component/compiler.rb | 4 ++-- lib/view_component/errors.rb | 9 ++++++--- lib/view_component/slotable.rb | 8 ++++++++ test/sandbox/test/slotable_test.rb | 22 ++++++++++++++++++++++ 5 files changed, 42 insertions(+), 5 deletions(-) diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 9ab9a22967..84a0c8f45c 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -10,6 +10,10 @@ nav_order: 5 ## main +* Resolve an issue where slots starting with `call` would cause a `NameError` + + *Blake Williams* + * Add `use_helper` API. *Reegan Viljoen* diff --git a/lib/view_component/compiler.rb b/lib/view_component/compiler.rb index 72c7367c46..c5ee5b8bd9 100644 --- a/lib/view_component/compiler.rb +++ b/lib/view_component/compiler.rb @@ -219,12 +219,12 @@ def inline_calls component_class.included_modules ) - view_component_ancestors.flat_map { |ancestor| ancestor.instance_methods(false).grep(/^call/) }.uniq + view_component_ancestors.flat_map { |ancestor| ancestor.instance_methods(false).grep(/^call(_|$)/) }.uniq end end def inline_calls_defined_on_self - @inline_calls_defined_on_self ||= component_class.instance_methods(false).grep(/^call/) + @inline_calls_defined_on_self ||= component_class.instance_methods(false).grep(/^call(_|$)/) end def variants diff --git a/lib/view_component/errors.rb b/lib/view_component/errors.rb index 36f9ee570c..b896f53d1c 100644 --- a/lib/view_component/errors.rb +++ b/lib/view_component/errors.rb @@ -104,7 +104,10 @@ class InvalidSlotDefinitionError < BaseError "string, or callable (that is proc, lambda, etc)" end - class SlotPredicateNameError < StandardError + class InvalidSlotNameError < StandardError + end + + class SlotPredicateNameError < InvalidSlotNameError MESSAGE = "COMPONENT declares a slot named SLOT_NAME, which ends with a question mark.\n\n" \ "This isn't allowed because the ViewComponent framework already provides predicate " \ @@ -126,7 +129,7 @@ def initialize(klass_name, slot_name) end end - class ReservedSingularSlotNameError < StandardError + class ReservedSingularSlotNameError < InvalidSlotNameError MESSAGE = "COMPONENT declares a slot named SLOT_NAME, which is a reserved word in the ViewComponent framework.\n\n" \ "To fix this issue, choose a different name." @@ -136,7 +139,7 @@ def initialize(klass_name, slot_name) end end - class ReservedPluralSlotNameError < StandardError + class ReservedPluralSlotNameError < InvalidSlotNameError MESSAGE = "COMPONENT declares a slot named SLOT_NAME, which is a reserved word in the ViewComponent framework.\n\n" \ "To fix this issue, choose a different name." diff --git a/lib/view_component/slotable.rb b/lib/view_component/slotable.rb index ecb4826a20..d46094b3cf 100644 --- a/lib/view_component/slotable.rb +++ b/lib/view_component/slotable.rb @@ -295,6 +295,7 @@ def validate_plural_slot_name(slot_name) raise ReservedPluralSlotNameError.new(name, slot_name) end + raise_if_slot_conflicts_with_call(slot_name) raise_if_slot_ends_with_question_mark(slot_name) raise_if_slot_registered(slot_name) end @@ -308,6 +309,7 @@ def validate_singular_slot_name(slot_name) raise ReservedSingularSlotNameError.new(name, slot_name) end + raise_if_slot_conflicts_with_call(slot_name) raise_if_slot_ends_with_question_mark(slot_name) raise_if_slot_registered(slot_name) end @@ -322,6 +324,12 @@ def raise_if_slot_registered(slot_name) 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_conflicts_with_call(slot_name) + if slot_name.start_with?("call_") + raise InvalidSlotNameError, "Slot cannot start with 'call_'. Please rename #{slot_name}" + end + end end def get_slot(slot_name) diff --git a/test/sandbox/test/slotable_test.rb b/test/sandbox/test/slotable_test.rb index 3a931167e6..086f418e59 100644 --- a/test/sandbox/test/slotable_test.rb +++ b/test/sandbox/test/slotable_test.rb @@ -719,4 +719,26 @@ def test_slot_with_content_shorthand assert component.title.content? end + + def test_slot_names_cannot_start_with_call_ + assert_raises ViewComponent::InvalidSlotNameError do + Class.new(ViewComponent::Base) do + renders_one :call_out_title + end + end + + assert_raises ViewComponent::InvalidSlotNameError do + Class.new(ViewComponent::Base) do + renders_many :call_out_titles + end + end + end + + def test_slot_names_can_start_with_call + assert_nothing_raised do + Class.new(ViewComponent::Base) do + renders_one :callhome_et + end + end + end end From 090ee0d118d94bc46008ea0bf166b2ca97e300c7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 Nov 2023 10:57:33 +0100 Subject: [PATCH 4/8] Bump net-imap from 0.4.2 to 0.4.4 (#1901) Bumps [net-imap](https://github.com/ruby/net-imap) from 0.4.2 to 0.4.4. - [Release notes](https://github.com/ruby/net-imap/releases) - [Commits](https://github.com/ruby/net-imap/compare/v0.4.2...v0.4.4) --- updated-dependencies: - dependency-name: net-imap dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Gemfile.lock | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index c5b1fa3608..c54a207e37 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -160,7 +160,7 @@ GEM mini_mime (1.1.5) mini_portile2 (2.8.4) minitest (5.20.0) - net-imap (0.4.2) + net-imap (0.4.4) date net-protocol net-pop (0.1.2) @@ -333,6 +333,9 @@ DEPENDENCIES jbuilder (~> 2) m (~> 1) minitest (~> 5.18) + net-imap + net-pop + net-smtp pry (~> 0.13) puma (~> 6) rails (~> 7.0.0) From 47191f0e96707e64ffa315843a38c1b5583ee056 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 Nov 2023 11:06:30 +0100 Subject: [PATCH 5/8] Bump cuprite from 0.14.3 to 0.15 (#1900) Bumps [cuprite](https://github.com/rubycdp/cuprite) from 0.14.3 to 0.15. - [Release notes](https://github.com/rubycdp/cuprite/releases) - [Changelog](https://github.com/rubycdp/cuprite/blob/main/CHANGELOG.md) - [Commits](https://github.com/rubycdp/cuprite/compare/v0.14.3...v0.15) --- updated-dependencies: - dependency-name: cuprite dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Gemfile | 2 +- Gemfile.lock | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Gemfile b/Gemfile index e4028ffb43..4cb0507415 100644 --- a/Gemfile +++ b/Gemfile @@ -11,7 +11,7 @@ gem "rails", (rails_version == "main") ? {git: "https://github.com/rails/rails", gem "rspec-rails", "~> 5" group :test do - gem "cuprite", "~> 0.8" + gem "cuprite", "~> 0.15" gem "puma", "~> 6" gem "selenium-webdriver", "4.9.0" # 4.9.1 requires Ruby 3+ diff --git a/Gemfile.lock b/Gemfile.lock index c54a207e37..93a216c4d0 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -74,7 +74,7 @@ GEM i18n (>= 1.6, < 2) minitest (>= 5.1) tzinfo (~> 2.0) - addressable (2.8.4) + addressable (2.8.5) public_suffix (>= 2.0.2, < 6.0) ansi (1.5.0) appraisal (2.5.0) @@ -104,9 +104,9 @@ GEM coderay (1.1.3) concurrent-ruby (1.2.2) crass (1.0.6) - cuprite (0.14.3) + cuprite (0.15) capybara (~> 3.0) - ferrum (~> 0.13.0) + ferrum (~> 0.14.0) date (3.3.3) debug (1.8.0) irb (>= 1.5.0) @@ -121,7 +121,7 @@ GEM rubocop smart_properties erubi (1.12.0) - ferrum (0.13) + ferrum (0.14) addressable (~> 2.5) concurrent-ruby (~> 1.1) webrick (~> 1.7) @@ -158,7 +158,7 @@ GEM matrix (0.4.2) method_source (1.0.0) mini_mime (1.1.5) - mini_portile2 (2.8.4) + mini_portile2 (2.8.5) minitest (5.20.0) net-imap (0.4.4) date @@ -180,10 +180,10 @@ GEM pry (0.14.2) coderay (~> 1.1) method_source (~> 1.0) - public_suffix (5.0.1) + public_suffix (5.0.3) puma (6.4.0) nio4r (~> 2.0) - racc (1.7.1) + racc (1.7.3) rack (2.2.8) rack-test (2.1.0) rack (>= 1.3) @@ -326,7 +326,7 @@ DEPENDENCIES better_html bundler (~> 2) capybara (~> 3) - cuprite (~> 0.8) + cuprite (~> 0.15) debug erb_lint haml (~> 6) From b11ba1f197e71cab1cc0758373a58c9b2e364755 Mon Sep 17 00:00:00 2001 From: Andrew Duthie Date: Mon, 6 Nov 2023 18:56:55 -0500 Subject: [PATCH 6/8] Allow setting method when using the test helper (#1805) --- docs/CHANGELOG.md | 4 ++++ docs/index.md | 1 + lib/view_component/test_helpers.rb | 14 +++++++++++++- .../app/components/current_page_component.rb | 6 +----- test/sandbox/config/routes.rb | 1 + test/sandbox/test/test_helper_test.rb | 12 ++++++++++-- 6 files changed, 30 insertions(+), 8 deletions(-) diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 84a0c8f45c..ffd121035f 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -26,6 +26,10 @@ nav_order: 5 *Nachiket Pusalkar* +* Allow setting method when using the `with_request_url` test helper. + + *Andrew Duthie* + ## 3.7.0 * Support Rails 7.1 in CI. diff --git a/docs/index.md b/docs/index.md index 393772ac4d..b20009efdb 100644 --- a/docs/index.md +++ b/docs/index.md @@ -211,6 +211,7 @@ ViewComponent is built by over a hundred members of the community, including: reeganviljoen thomascchen milk1000cc +aduth ## Who uses ViewComponent? diff --git a/lib/view_component/test_helpers.rb b/lib/view_component/test_helpers.rb index 3a24b1aa31..02d1a9b7c4 100644 --- a/lib/view_component/test_helpers.rb +++ b/lib/view_component/test_helpers.rb @@ -163,10 +163,20 @@ def with_controller_class(klass) # end # ``` # + # To specify a request method, pass the method param: + # + # ```ruby + # with_request_url("/users/42", method: "POST") do + # render_inline(MyComponent.new) + # end + # ``` + # # @param path [String] The path to set for the current request. # @param host [String] The host to set for the current request. - def with_request_url(full_path, host: nil) + # @param method [String] The request method to set for the current request. + def with_request_url(full_path, host: nil, method: nil) old_request_host = vc_test_request.host + old_request_method = vc_test_request.request_method old_request_path_info = vc_test_request.path_info old_request_path_parameters = vc_test_request.path_parameters old_request_query_parameters = vc_test_request.query_parameters @@ -177,6 +187,7 @@ def with_request_url(full_path, host: nil) vc_test_request.instance_variable_set(:@fullpath, full_path) vc_test_request.instance_variable_set(:@original_fullpath, full_path) vc_test_request.host = host if host + vc_test_request.request_method = method if method vc_test_request.path_info = path vc_test_request.path_parameters = Rails.application.routes.recognize_path_with_request(vc_test_request, path, {}) vc_test_request.set_header("action_dispatch.request.query_parameters", @@ -185,6 +196,7 @@ def with_request_url(full_path, host: nil) yield ensure vc_test_request.host = old_request_host + vc_test_request.request_method = old_request_method vc_test_request.path_info = old_request_path_info vc_test_request.path_parameters = old_request_path_parameters vc_test_request.set_header("action_dispatch.request.query_parameters", old_request_query_parameters) diff --git a/test/sandbox/app/components/current_page_component.rb b/test/sandbox/app/components/current_page_component.rb index 559862199d..afd1c327e7 100644 --- a/test/sandbox/app/components/current_page_component.rb +++ b/test/sandbox/app/components/current_page_component.rb @@ -2,10 +2,6 @@ class CurrentPageComponent < ViewComponent::Base def text - if current_page?("/slots") - "Inside /slots" - else - "Outside /slots" - end + "#{current_page?("/slots") ? "Inside" : "Outside"} /slots (#{request.method} #{request.path})" end end diff --git a/test/sandbox/config/routes.rb b/test/sandbox/config/routes.rb index e921c0003d..afbb357be9 100644 --- a/test/sandbox/config/routes.rb +++ b/test/sandbox/config/routes.rb @@ -29,6 +29,7 @@ get :cached_partial, to: "integration_examples#cached_partial" get :inherited_sidecar, to: "integration_examples#inherited_sidecar" get :inherited_from_uncompilable_component, to: "integration_examples#inherited_from_uncompilable_component" + post :create, to: "integration_examples#create" constraints(lambda { |request| request.env["warden"].authenticate! }) do get :constraints_with_env, to: "integration_examples#index" diff --git a/test/sandbox/test/test_helper_test.rb b/test/sandbox/test/test_helper_test.rb index 90339a10fc..c55dfc0ebf 100644 --- a/test/sandbox/test/test_helper_test.rb +++ b/test/sandbox/test/test_helper_test.rb @@ -8,7 +8,7 @@ def test_with_request_url_inside_slots_path render_inline(CurrentPageComponent.new) end - assert_selector("div", text: "Inside /slots") + assert_selector("div", text: "Inside /slots (GET /slots)") end def test_with_request_url_outside_slots_path @@ -16,7 +16,15 @@ def test_with_request_url_outside_slots_path render_inline(CurrentPageComponent.new) end - assert_selector("div", text: "Outside /slots") + assert_selector("div", text: "Outside /slots (GET /)") + end + + def test_with_request_url_specifying_method + with_request_url "/create", method: "POST" do + render_inline(CurrentPageComponent.new) + end + + assert_selector("div", text: "Outside /slots (POST /create)") end def test_with_request_url_under_constraint From 00cdde88e7b9d45e557edd70fd4839b32276a744 Mon Sep 17 00:00:00 2001 From: Reegan Viljoen <62689748+reeganviljoen@users.noreply.github.com> Date: Tue, 7 Nov 2023 21:22:01 +0200 Subject: [PATCH 7/8] Don't add ActionDispatch::Static middleware continued (#1892) * Don't add ActionDispatch::Static middleware In the case that rails do not serve static files is not necessary to add ActionDispatch::Static middleware. Making possible to deploy ViewComponenets previews on a production environment where Nginx or Apache is managing the static files. * Apply suggestions from code review Co-authored-by: Joel Hawksley * Update index.md * add: prism cdn if no asset precompiler found * edit: change prism cdn version to 1.28 * Update app/helpers/preview_helper.rb Co-authored-by: Cameron Dutro * Update app/helpers/preview_helper.rb Co-authored-by: Cameron Dutro * Update app/helpers/preview_helper.rb Co-authored-by: Cameron Dutro * Update app/helpers/preview_helper.rb Co-authored-by: Cameron Dutro * Update lib/view_component/engine.rb Co-authored-by: Cameron Dutro * edit: fix brocken tests * edit: refactor tests * edit: fix for rails > 6.1 * edit: fix lint issues * Update lib/view_component/engine.rb Co-authored-by: Hans Lemuet --------- Co-authored-by: Daniel Gonzalez Co-authored-by: Joel Hawksley Co-authored-by: Cameron Dutro Co-authored-by: Hans Lemuet --- app/helpers/preview_helper.rb | 14 ++++++++ .../view_components/_preview_source.html.erb | 4 +-- docs/CHANGELOG.md | 5 +++ docs/index.md | 1 + lib/view_component/engine.rb | 6 +++- test/sandbox/test/preview_helper_test.rb | 32 +++++++++++++++++++ test/view_component/engine_test.rb | 10 ++++++ 7 files changed, 69 insertions(+), 3 deletions(-) create mode 100644 test/view_component/engine_test.rb diff --git a/app/helpers/preview_helper.rb b/app/helpers/preview_helper.rb index 0485b47751..222334985e 100644 --- a/app/helpers/preview_helper.rb +++ b/app/helpers/preview_helper.rb @@ -1,6 +1,8 @@ # frozen_string_literal: true module PreviewHelper + include ActionView::Helpers::AssetUrlHelper if Rails.version.to_f < 6.1 + AVAILABLE_PRISM_LANGUAGES = %w[ruby erb haml] FALLBACK_LANGUAGE = "ruby" @@ -10,6 +12,14 @@ def preview_source render "preview_source" end + def prism_css_source_url + serve_static_preview_assets? ? asset_path("prism.css", skip_pipeline: true) : "https://cdn.jsdelivr.net/npm/prismjs@1.28.0/themes/prism.min.css" + end + + def prism_js_source_url + serve_static_preview_assets? ? asset_path("prism.min.js", skip_pipeline: true) : "https://cdn.jsdelivr.net/npm/prismjs@1.28.0/prism.min.js" + end + def find_template_data(lookup_context:, template_identifier:) template = lookup_context.find_template(template_identifier) @@ -62,4 +72,8 @@ def prism_language_name_by_template_path(template_file_path:) language end + + def serve_static_preview_assets? + ViewComponent::Base.config.show_previews && Rails.application.config.public_file_server.enabled + end end diff --git a/app/views/view_components/_preview_source.html.erb b/app/views/view_components/_preview_source.html.erb index f1259f291e..606b8ac80a 100644 --- a/app/views/view_components/_preview_source.html.erb +++ b/app/views/view_components/_preview_source.html.erb @@ -1,4 +1,4 @@ - +

Source:

@@ -14,4 +14,4 @@
     <% end %>
   
- + diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index ffd121035f..b66e6ec701 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -10,6 +10,11 @@ nav_order: 5 ## main +* Don't add ActionDispatch::Static middleware unless `public_file_server.enabled`. + + *Daniel Gonzalez* + *Reegan Viljoen* + * 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 b20009efdb..24f750a5c6 100644 --- a/docs/index.md +++ b/docs/index.md @@ -204,6 +204,7 @@ ViewComponent is built by over a hundred members of the community, including: xronos-i-am yykamei matheuspolicamilo +danigonza erinnachen ihollander svetlins diff --git a/lib/view_component/engine.rb b/lib/view_component/engine.rb index 7c3740bceb..47618fe261 100644 --- a/lib/view_component/engine.rb +++ b/lib/view_component/engine.rb @@ -110,11 +110,15 @@ class Engine < Rails::Engine # :nodoc: end initializer "static assets" do |app| - if app.config.view_component.show_previews + if serve_static_preview_assets?(app.config) app.middleware.use(::ActionDispatch::Static, "#{root}/app/assets/vendor") end end + def serve_static_preview_assets?(app_config) + app_config.view_component.show_previews && app_config.public_file_server.enabled + end + initializer "compiler mode" do |_app| ViewComponent::Compiler.mode = if Rails.env.development? || Rails.env.test? ViewComponent::Compiler::DEVELOPMENT_MODE diff --git a/test/sandbox/test/preview_helper_test.rb b/test/sandbox/test/preview_helper_test.rb index 108a8a71dd..5921a525d1 100644 --- a/test/sandbox/test/preview_helper_test.rb +++ b/test/sandbox/test/preview_helper_test.rb @@ -155,5 +155,37 @@ def test_raises_with_conflict_in_template_resolution assert_equal("Found multiple templates for #{template_identifier}.", exception.message) end end + + def test_prism_css_source_url_with_asset_pipeline + Rails.application.config.public_file_server.stub(:enabled, true) do + if Rails.version.to_f >= 6.1 + assert_equal "/assets/prism.css", PreviewHelper.prism_css_source_url + else + assert_equal "/prism.css", PreviewHelper.prism_css_source_url + end + end + end + + def test_prism_css_source_url_with_no_asset_pipeline + Rails.application.config.public_file_server.stub(:enabled, false) do + assert_equal "https://cdn.jsdelivr.net/npm/prismjs@1.28.0/themes/prism.min.css", PreviewHelper.prism_css_source_url + end + end + + def test_prism_js_source_with_asset_pipeline + Rails.application.config.public_file_server.stub(:enabled, true) do + if Rails.version.to_f >= 6.1 + assert_equal "/assets/prism.min.js", PreviewHelper.prism_js_source_url + else + assert_equal "/prism.min.js", PreviewHelper.prism_js_source_url + end + end + end + + def test_prism_js_source_url_with_no_asset_pipeline + Rails.application.config.public_file_server.stub(:enabled, false) do + assert_equal "https://cdn.jsdelivr.net/npm/prismjs@1.28.0/prism.min.js", PreviewHelper.prism_js_source_url + end + end end end diff --git a/test/view_component/engine_test.rb b/test/view_component/engine_test.rb new file mode 100644 index 0000000000..5c5c037260 --- /dev/null +++ b/test/view_component/engine_test.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true + +require "test_helper" + +class ViewComponent::EngineTest < ActionDispatch::IntegrationTest + def test_serve_static_previews? + app.config.public_file_server.enabled = false + refute ViewComponent::Engine.instance.serve_static_preview_assets?(app.config) + end +end From 0820ce829b0519bbc1573df6001a36750d322e2d Mon Sep 17 00:00:00 2001 From: halo Date: Wed, 8 Nov 2023 21:40:58 +0100 Subject: [PATCH 8/8] Use native String#end_with?, not the Rails wrapper (#1905) There is technically no need to depend on this core extension: https://github.com/rails/rails/blob/939fd3bc41bbb90194e4b93a001c803bdceb592c/activesupport/lib/active_support/core_ext/string/starts_ends_with.rb --- docs/CHANGELOG.md | 4 ++++ lib/view_component/slotable.rb | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index b66e6ec701..236db227e5 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -10,6 +10,10 @@ nav_order: 5 ## main +* Replace usage of `String#ends_with?` with `String#end_with?` to reduce the dependency on ActiveSupport core extensions. + + *halo* + * Don't add ActionDispatch::Static middleware unless `public_file_server.enabled`. *Daniel Gonzalez* diff --git a/lib/view_component/slotable.rb b/lib/view_component/slotable.rb index d46094b3cf..b38ab3100f 100644 --- a/lib/view_component/slotable.rb +++ b/lib/view_component/slotable.rb @@ -322,7 +322,7 @@ def raise_if_slot_registered(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?("?") + raise SlotPredicateNameError.new(name, slot_name) if slot_name.to_s.end_with?("?") end def raise_if_slot_conflicts_with_call(slot_name)