Skip to content

Remove actionview base #2280

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 10 commits into from
Closed
Show file tree
Hide file tree
Changes from all 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
29 changes: 0 additions & 29 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,46 +31,18 @@ jobs:
include:
- ruby_version: "3.0"
rails_version: "6.1"
mode: "capture_patch_enabled"
- ruby_version: "3.0"
rails_version: "6.1"
mode: "capture_patch_disabled"
- ruby_version: "3.1"
rails_version: "7.0"
mode: "capture_patch_enabled"
- ruby_version: "3.1"
rails_version: "7.0"
mode: "capture_patch_disabled"
- ruby_version: "3.2"
rails_version: "7.1"
mode: "capture_patch_enabled"
- ruby_version: "3.2"
rails_version: "7.1"
mode: "capture_patch_disabled"
- ruby_version: "3.3"
rails_version: "7.2"
mode: "capture_patch_disabled"
- ruby_version: "3.3"
rails_version: "7.2"
mode: "capture_patch_enabled"
- ruby_version: "3.3"
rails_version: "8.0"
mode: "capture_patch_disabled"
- ruby_version: "3.3"
rails_version: "8.0"
mode: "capture_patch_enabled"
- ruby_version: "3.4"
rails_version: "8.0"
mode: "capture_patch_disabled"
- ruby_version: "3.4"
rails_version: "8.0"
mode: "capture_patch_enabled"
- ruby_version: "head"
rails_version: "main"
mode: "capture_patch_disabled"
- ruby_version: "head"
rails_version: "main"
mode: "capture_patch_enabled"
env:
BUNDLE_GEMFILE: gemfiles/rails_${{ matrix.rails_version }}.gemfile
steps:
Expand All @@ -91,7 +63,6 @@ jobs:
RAISE_ON_WARNING: 1
RAILS_VERSION: ${{ matrix.rails_version }}
RUBY_VERSION: ${{ matrix.ruby_version }}
CAPTURE_PATCH_ENABLED: ${{ matrix.mode == 'capture_patch_enabled' && 'true' || 'false' }}
- name: Upload coverage results
uses: actions/[email protected]
if: always()
Expand Down
47 changes: 37 additions & 10 deletions lib/view_component/base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,21 @@
require "view_component/with_content_helper"
require "view_component/use_helpers"

module ActionView
class OutputBuffer
def with_buffer(buf = nil)
new_buffer = buf || +""
old_buffer, @raw_buffer = @raw_buffer, new_buffer
yield
new_buffer
ensure
@raw_buffer = old_buffer
end
end
end

module ViewComponent
class Base < ActionView::Base
class Base
class << self
delegate(*ViewComponent::Config.defaults.keys, to: :config)

Expand All @@ -33,6 +46,11 @@ def config
end
end

include ActionView::Helpers

include ERB::Escape
include ActiveSupport::CoreExt::ERBUtil

include ViewComponent::InlineTemplate
include ViewComponent::UseHelpers
include ViewComponent::Slotable
Expand All @@ -48,6 +66,9 @@ def config
# For Content Security Policy nonces
delegate :content_security_policy_nonce, to: :helpers

# HTML construction methods
delegate :output_buffer, :lookup_context, :view_renderer, :view_flow, to: :helpers

# Config option that strips trailing whitespace in templates before compiling them.
class_attribute :__vc_strip_trailing_whitespace, instance_accessor: false, instance_predicate: false
self.__vc_strip_trailing_whitespace = false # class_attribute:default doesn't work until Rails 5.2
Expand All @@ -64,7 +85,7 @@ def config
# @param view_context [ActionView::Base] The original view context.
# @return [void]
def set_original_view_context(view_context)
self.__vc_original_view_context = view_context
# no-op
end

# Entrypoint for rendering components.
Expand All @@ -81,7 +102,7 @@ def render_in(view_context, &block)
@view_context = view_context
self.__vc_original_view_context ||= view_context

@output_buffer = ActionView::OutputBuffer.new
@output_buffer = view_context.output_buffer

@lookup_context ||= view_context.lookup_context

Expand Down Expand Up @@ -112,14 +133,20 @@ def render_in(view_context, &block)
before_render

if render?
rendered_template = render_template_for(@__vc_variant, __vc_request&.format&.to_sym).to_s
value = nil

@output_buffer.with_buffer do
rendered_template = render_template_for(@__vc_variant, __vc_request&.format&.to_sym).to_s

# Avoid allocating new string when output_preamble and output_postamble are blank
if output_preamble.blank? && output_postamble.blank?
rendered_template
else
safe_output_preamble + rendered_template + safe_output_postamble
# Avoid allocating new string when output_preamble and output_postamble are blank
value = if output_preamble.blank? && output_postamble.blank?
rendered_template
else
safe_output_preamble + rendered_template + safe_output_postamble
end
end

value
else
""
end
Expand Down Expand Up @@ -211,7 +238,7 @@ def initialize(*)
def render(options = {}, args = {}, &block)
if options.respond_to?(:set_original_view_context)
options.set_original_view_context(self.__vc_original_view_context)
super
@view_context.render(options, args, &block)
else
__vc_original_view_context.render(options, args, &block)
end
Expand Down
44 changes: 0 additions & 44 deletions lib/view_component/capture_compatibility.rb

This file was deleted.

8 changes: 0 additions & 8 deletions lib/view_component/collection.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,8 @@ class Collection

delegate :size, to: :@collection

attr_accessor :__vc_original_view_context

def set_original_view_context(view_context)
self.__vc_original_view_context = view_context
end

def render_in(view_context, &block)
components.map do |component|
component.set_original_view_context(__vc_original_view_context)
component.render_in(view_context, &block)
end.join(rendered_spacer(view_context)).html_safe
end
Expand Down Expand Up @@ -73,7 +66,6 @@ def component_options(item, iterator)

def rendered_spacer(view_context)
if @spacer_component
@spacer_component.set_original_view_context(__vc_original_view_context)
@spacer_component.render_in(view_context)
else
""
Expand Down
41 changes: 33 additions & 8 deletions lib/view_component/engine.rb
Original file line number Diff line number Diff line change
Expand Up @@ -68,14 +68,6 @@ class Engine < Rails::Engine # :nodoc:
end
end

# :nocov:
initializer "view_component.enable_capture_patch" do |app|
ActiveSupport.on_load(:view_component) do
ActionView::Base.include(ViewComponent::CaptureCompatibility) if app.config.view_component.capture_compatibility_patch_enabled
end
end
# :nocov:

initializer "view_component.set_autoload_paths" do |app|
options = app.config.view_component

Expand Down Expand Up @@ -131,6 +123,39 @@ class Engine < Rails::Engine # :nodoc:
# :nocov:
end

initializer "view_component.propshaft_support" do |_app|
ActiveSupport.on_load(:view_component) do
if defined?(Propshaft)
include Propshaft::Helper
end
end
end

config.after_initialize do |app|
ActiveSupport.on_load(:view_component) do
if defined?(Sprockets::Rails)
include Sprockets::Rails::Helper

# Copy relevant config to VC context
# See: https://github.com/rails/sprockets-rails/blob/266ec49f3c7c96018dd75f9dc4f9b62fe3f7eecf/lib/sprockets/railtie.rb#L245
self.debug_assets = app.config.assets.debug
self.digest_assets = app.config.assets.digest
self.assets_prefix = app.config.assets.prefix
self.assets_precompile = app.config.assets.precompile

self.assets_environment = app.assets
self.assets_manifest = app.assets_manifest

self.resolve_assets_with = app.config.assets.resolve_with

self.check_precompiled_asset = app.config.assets.check_precompiled_asset
self.unknown_asset_fallback = app.config.assets.unknown_asset_fallback
# Expose the app precompiled asset check to the view
self.precompiled_asset_checker = -> logical_path { app.asset_precompiled? logical_path }
end
end
end

initializer "static assets" do |app|
if serve_static_preview_assets?(app.config)
app.middleware.use(::ActionDispatch::Static, "#{root}/app/assets/vendor")
Expand Down
1 change: 0 additions & 1 deletion lib/view_component/render_component_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
module ViewComponent
module RenderComponentHelper # :nodoc:
def render_component(component, &block)
component.set_original_view_context(__vc_original_view_context) if is_a?(ViewComponent::Base)
component.render_in(self, &block)
end
end
Expand Down
10 changes: 1 addition & 9 deletions lib/view_component/slot.rb
Original file line number Diff line number Diff line change
Expand Up @@ -58,15 +58,7 @@ def to_s
if defined?(@__vc_content_block)
# render_in is faster than `parent.render`
@__vc_component_instance.render_in(view_context) do |*args|
return @__vc_content_block.call(*args) if @__vc_content_block&.source_location.nil?

block_context = @__vc_content_block.binding.receiver

if block_context.class < ActionView::Base
block_context.capture(*args, &@__vc_content_block)
else
@__vc_content_block.call(*args)
end
@__vc_content_block.call(*args)
end
else
@__vc_component_instance.render_in(view_context)
Expand Down
3 changes: 2 additions & 1 deletion lib/view_component/template.rb
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,9 @@ def compile_to_component
@component.silence_redefinition_of_method(@call_method_name)

# rubocop:disable Style/EvalWithLocation
@component.class_eval <<-RUBY, @path, @lineno
@component.class_eval <<-RUBY, @path, @lineno - 1
def #{@call_method_name}
@view_context.instance_variable_set(:@virtual_path, virtual_path)
#{compiled_source}
end
RUBY
Expand Down
6 changes: 3 additions & 3 deletions lib/view_component/translatable.rb
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ def store_translations(locale, data, options = EMPTY_HASH)
def translate(key = nil, **options)
raise ViewComponent::TranslateCalledBeforeRenderError if view_context.nil?

return super unless i18n_backend
return @view_context.translate(key, **options) unless i18n_backend
return key.map { |k| translate(k, **options) } if key.is_a?(Array)

locale = options.delete(:locale) || ::I18n.locale
Expand All @@ -108,13 +108,13 @@ def translate(key = nil, **options)

# Fallback to the global translations
if translated.is_a? ::I18n::MissingTranslation
return super(key, locale: locale, **options)
return @view_context.translate(key, locale: locale, **options)
end

translated = html_safe_translation(translated) if as_html
translated
else
super(key, locale: locale, **options)
@view_context.translate(key, locale: locale, **options)
end
end
alias_method :t, :translate
Expand Down
1 change: 0 additions & 1 deletion test/sandbox/app/components/renders_non_component.html.erb

This file was deleted.

20 changes: 0 additions & 20 deletions test/sandbox/app/components/renders_non_component.rb

This file was deleted.

1 change: 0 additions & 1 deletion test/sandbox/config/environments/test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@
config.view_component.render_monkey_patch_enabled = true
config.view_component.show_previews_source = true
config.view_component.test_controller = "IntegrationExamplesController"
config.view_component.capture_compatibility_patch_enabled = ENV["CAPTURE_PATCH_ENABLED"] == "true"

# Tell Action Mailer not to deliver emails to the real world.
# The :test delivery method accumulates sent emails in the
Expand Down
Loading
Loading