Fix helpers not reloading in previews (#1075)

This commit is contained in:
Jonathan del Strother 2023-05-15 18:20:42 +01:00 коммит произвёл GitHub
Родитель 16bd042b62
Коммит 18f97812f1
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
14 изменённых файлов: 124 добавлений и 26 удалений

6
.github/workflows/ci.yml поставляемый
Просмотреть файл

@ -71,10 +71,12 @@ jobs:
run: |
bundle config path vendor/bundle
bundle update
bundle exec rake test spec
# Code-reloading isn't compatible with simplecov, so we need to run once
# to collect coverage, and again to test reloads.
MEASURE_COVERAGE=true bundle exec rake test spec
ENABLE_RELOADING=true bundle exec rake test spec
env:
RAISE_ON_WARNING: 1
MEASURE_COVERAGE: true
RAILS_VERSION: ${{ matrix.rails_version }}
CAPTURE_PATCH_ENABLED: ${{ matrix.mode == 'capture_patch_enabled' && 'true' || 'false' }}
- name: Upload coverage results

Просмотреть файл

@ -11,6 +11,10 @@ module ViewComponent
before_action :require_local!, unless: :show_previews?
content_security_policy(false) if respond_to?(:content_security_policy)
# Including helpers here ensures that we're loading the
# latest version of helpers if code-reloading is enabled
helper :all if include_all_helpers
end
def index

Просмотреть файл

@ -10,17 +10,21 @@ nav_order: 5
## main
* Fix helpers not reloading in development.
*Jonathan del Strother*
* Add `SECURITY.md`.
*Joel Hawksley*
*Joel Hawksley*
* Add Ophelos to list of companies using ViewComponent.
*Graham Rogers*
*Graham Rogers*
* Add FlightLogger to list of companies using ViewComponent.
*Joseph Carpenter*
*Joseph Carpenter*
### v3.0.0

Просмотреть файл

@ -19,7 +19,7 @@ module ViewComponent
# Returns the current config.
#
# @return [ViewComponent::Config]
# @return [ActiveSupport::OrderedOptions]
def config
@config ||= ActiveSupport::OrderedOptions.new
end

Просмотреть файл

@ -1,11 +1,11 @@
# frozen_string_literal: true
class OtherFormBuilder < ActionView::Helpers::FormBuilder
def text_field(*)
"changed by default form builder"
end
end
class DefaultFormBuilderController < ActionController::Base
class OtherFormBuilder < ActionView::Helpers::FormBuilder
def text_field(*)
"changed by default form builder"
end
end
default_form_builder OtherFormBuilder
end

Просмотреть файл

@ -34,6 +34,10 @@ class IntegrationExamplesController < ActionController::Base
render_component(ControllerInlineComponent.new(message: "bar"))
end
def helpers_proxy_component
render(plain: render_to_string(HelpersProxyComponent.new))
end
def controller_to_string_render_component
render(plain: render_component_to_string(ControllerInlineComponent.new(message: "bar")))
end

Просмотреть файл

@ -7,7 +7,10 @@ Sandbox::Application.configure do
# test suite. You never need to work with it otherwise. Remember that
# your test database is "scratch space" for the test suite and is wiped
# and recreated between test runs. Don't rely on the data there!
config.cache_classes = true
# `cache_classes=false` is necessary to test code-reloading for people using VC in development.
# However, it's incompatible with collecting simplecov coverage reports.
config.cache_classes = !ENV["ENABLE_RELOADING"]
# Show full error reports and disable caching
config.consider_all_requests_local = true

Просмотреть файл

@ -33,4 +33,5 @@ Sandbox::Application.routes.draw do
constraints(lambda { |request| request.env["warden"].authenticate! }) do
get :constraints_with_env, to: "integration_examples#index"
end
get :helpers_proxy_component, to: "integration_examples#helpers_proxy_component"
end

Просмотреть файл

@ -0,0 +1,7 @@
# frozen_string_literal: true
class HelpersProxyComponentPreview < ViewComponent::Preview
def default
render(HelpersProxyComponent.new)
end
end

Просмотреть файл

@ -52,21 +52,21 @@ class IntegrationTest < ActionDispatch::IntegrationTest
end
def test_template_changes_are_not_reflected_on_new_request_when_cache_template_loading_is_true
# cache_template_loading is set to true on the initializer
with_template_caching do
get "/controller_inline"
assert_select("div", "bar")
assert_response :success
get "/controller_inline"
assert_select("div", "bar")
assert_response :success
modify_file "app/components/controller_inline_component.html.erb", "<div>Goodbye world!</div>" do
get "/controller_inline"
assert_select("div", "bar")
assert_response :success
end
modify_file "app/components/controller_inline_component.html.erb", "<div>Goodbye world!</div>" do
get "/controller_inline"
assert_select("div", "bar")
assert_response :success
end
get "/controller_inline"
assert_select("div", "bar")
assert_response :success
end
def test_template_changes_are_reflected_on_new_request_when_cache_template_loading_is_false
@ -127,6 +127,58 @@ class IntegrationTest < ActionDispatch::IntegrationTest
end
end
def test_helper_changes_are_reflected_on_new_request
skip if Rails.application.config.cache_classes
get "/helpers_proxy_component"
assert_select("div", "Hello helper method")
assert_response :success
helper = <<~RUBY
module MessageHelper
def message
"Goodbye world!"
end
end
RUBY
modify_file "app/helpers/message_helper.rb", helper do
get "/helpers_proxy_component"
assert_select("div", "Goodbye world!")
assert_response :success
end
get "/helpers_proxy_component"
assert_select("div", "Hello helper method")
assert_response :success
end
def test_helper_changes_are_reflected_on_new_request_with_previews
skip if Rails.application.config.cache_classes
with_preview_route("/previews") do
get "/previews/helpers_proxy_component/default"
assert_select("div", "Hello helper method")
assert_response :success
helper = <<~RUBY
module MessageHelper
def message
"Goodbye world!"
end
end
RUBY
modify_file "app/helpers/message_helper.rb", helper do
get "/previews/helpers_proxy_component/default"
assert_select("div", "Goodbye world!")
assert_response :success
end
get "/previews/helpers_proxy_component/default"
assert_select("div", "Hello helper method")
assert_response :success
end
end
def test_rendering_component_in_a_controller_using_render_to_string
get "/controller_inline_baseline"

Просмотреть файл

@ -5,7 +5,9 @@ require "test_helper"
module ViewComponent
class RakeTasksTest < TestCase
def setup
Sandbox::Application.load_tasks
Kernel.silence_warnings do
Sandbox::Application.load_tasks
end
end
def test_statsetup_task

Просмотреть файл

@ -417,10 +417,18 @@ class RenderingTest < ViewComponent::TestCase
end
def test_compiles_unrendered_component
# The UnreferencedComponent will get compiled at boot,
# but that might have been thrown away if code-reloading is enabled
skip unless Rails.env.cache_classes?
assert UnreferencedComponent.compiled?
end
def test_compiles_components_without_initializers
# MissingInitializerComponent will get compiled at boot,
# but that might have been thrown away if code-reloading is enabled
skip unless Rails.env.cache_classes?
assert MissingInitializerComponent.compiled?
end
@ -923,8 +931,8 @@ class RenderingTest < ViewComponent::TestCase
# undo the changes made by self.class.compile and friends, forcing a compile the next time
# #render_template_for is called. This shouldn't be necessary except in the test environment,
# since eager loading is turned on here.
Object.send(:remove_const, :MyComponent)
Object.send(:remove_const, :InheritedWithOwnTemplateComponent)
Object.send(:remove_const, :MyComponent) if defined?(MyComponent)
Object.send(:remove_const, :InheritedWithOwnTemplateComponent) if defined?(InheritedWithOwnTemplateComponent)
load "test/sandbox/app/components/my_component.rb"
load "test/sandbox/app/components/inherited_with_own_template_component.rb"

Просмотреть файл

@ -4,7 +4,9 @@ require "test_helper"
class TasksTest < ActiveSupport::TestCase
setup do
Rails.application.load_tasks
Kernel.silence_warnings do
Rails.application.load_tasks
end
end
teardown do

Просмотреть файл

@ -114,6 +114,15 @@ def with_generate_sidecar(enabled, &block)
with_generate_option(:sidecar, enabled, &block)
end
def with_template_caching
old_cache_template_loading = ActionView::Base.cache_template_loading
ActionView::Base.cache_template_loading = true
yield
ensure
ActionView::Base.cache_template_loading = old_cache_template_loading
end
def with_new_cache
old_cache = ViewComponent::CompileCache.cache
ViewComponent::CompileCache.cache = Set.new