diff --git a/config.ru b/config.ru index ec59e1b1..d6d219b5 100644 --- a/config.ru +++ b/config.ru @@ -11,6 +11,10 @@ Combustion.initialize! :all do config.logger = ActiveSupport::TaggedLogging.new(Logger.new(nil)) config.log_level = :fatal + config.cache_classes = false + + config.file_watcher = ActiveSupport::EventedFileUpdateChecker + config.view_component.preview_paths << Rails.root.join("test/components/previews") config.view_component.default_preview_layout = "component_preview" diff --git a/lib/view_component/form/test_helpers.rb b/lib/view_component/form/test_helpers.rb index f16eb92e..38ddc452 100644 --- a/lib/view_component/form/test_helpers.rb +++ b/lib/view_component/form/test_helpers.rb @@ -7,14 +7,35 @@ module ViewComponent module Form module TestHelpers - def form_with(object, builder: ViewComponent::Form::Builder, **options) - builder.new(object_name, object, template, options) + include ActionView::ModelNaming + + # See: https://github.com/rails/rails/blob/83217025a171593547d1268651b446d3533e2019/actionview/lib/action_view/helpers/form_helper.rb#L737 + def form_with(model: nil, scope: nil, **options) + if model + model = model.last if model.is_a?(Array) + scope ||= model_name_from_record_or_class(model).param_key + end + + instanciate_form_builder(scope, model, options) end - def object_name - :user + # See: https://github.com/rails/rails/blob/83217025a171593547d1268651b446d3533e2019/actionview/lib/action_view/helpers/form_helper.rb#L1561 + def instanciate_form_builder(record_name, record_object = nil, **options) + case record_name + when String, Symbol + object = record_object + object_name = record_name + else + object = record_name + object_name = model_name_from_record_or_class(object).param_key if object + end + + builder = options[:builder] || ViewComponent::Form::Builder + builder.new(object_name, object, template, options) end + private + if Gem::Version.new(Rails::VERSION::STRING) >= Gem::Version.new("6.1") def template lookup_context = ActionView::LookupContext.new(ActionController::Base.view_paths) diff --git a/spec/internal/app/models/user.rb b/spec/internal/app/models/user.rb new file mode 100644 index 00000000..4a57cf07 --- /dev/null +++ b/spec/internal/app/models/user.rb @@ -0,0 +1,2 @@ +class User < ActiveRecord::Base +end diff --git a/spec/internal/config/routes.rb b/spec/internal/config/routes.rb index c46e0943..9fe1c1b2 100644 --- a/spec/internal/config/routes.rb +++ b/spec/internal/config/routes.rb @@ -3,5 +3,5 @@ Rails.application.routes.draw do # Add your own routes here, or remove this file if you don't have need for it. - mount Lookbook::Engine, at: "/" if Rails.env.development? + mount Lookbook::Engine, at: "/lookbook" if Rails.env.development? # TODO: path to "/" but broke cable path end diff --git a/spec/internal/db/schema.rb b/spec/internal/db/schema.rb index 7b6342ba..dedc467e 100644 --- a/spec/internal/db/schema.rb +++ b/spec/internal/db/schema.rb @@ -33,6 +33,11 @@ create_table(:cities, force: true) do |t| t.belongs_to :country + end + + create_table(:users, force: true) do |t| + t.string :first_name + t.string :last_name t.timestamps end end diff --git a/spec/internal/test/components/previews/view_component/form/label_component_preview.rb b/spec/internal/test/components/previews/view_component/form/label_component_preview.rb index 5f9b0c58..58f690c5 100644 --- a/spec/internal/test/components/previews/view_component/form/label_component_preview.rb +++ b/spec/internal/test/components/previews/view_component/form/label_component_preview.rb @@ -1,34 +1,21 @@ # frozen_string_literal: true +require "view_component/form/test_helpers" + module ViewComponent module Form class LabelComponentPreview < ViewComponent::Preview - def test - render ViewComponent::Form::LabelComponent.new(form_builder, object_name, :first_name) + include ViewComponent::Form::TestHelpers + + def default + # TODO: maybe stop passing object_name to components since it is accessing from form_builder (delegate in BaseComponent) + render ViewComponent::Form::LabelComponent.new(form_builder, form_builder.object_name, :first_name) end private def form_builder - @form_builder ||= ViewComponent::Form::Builder.new(object_name, object, template, {}) - end - - def object - OpenStruct.new - end - - def object_name - :user - end - - def template - lookup_context = ActionView::LookupContext.new(ActionController::Base.view_paths) - - if Gem::Version.new(Rails::VERSION::STRING) >= Gem::Version.new("6.1") - ActionView::Base.new(lookup_context, {}, ActionController::Base.new) - else - ActionView::Base.new(lookup_context, {}) - end + instanciate_form_builder(User.new) end end end diff --git a/spec/internal/test/components/previews/view_component/form/submit_component_preview.rb b/spec/internal/test/components/previews/view_component/form/submit_component_preview.rb new file mode 100644 index 00000000..6a2d8daf --- /dev/null +++ b/spec/internal/test/components/previews/view_component/form/submit_component_preview.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true + +require "view_component/form/test_helpers" + +module ViewComponent + module Form + class SubmitComponentPreview < ViewComponent::Preview + include ViewComponent::Form::TestHelpers + + def default + # TODO: maybe stop passing object_name to components since it is accessing from form_builder (delegate in BaseComponent) + render ViewComponent::Form::SubmitComponent.new(form_builder, form_builder.object_name) + end + + private + + def form_builder + instanciate_form_builder(User.new) + end + end + end +end diff --git a/spec/internal/test/components/previews/view_component/form/text_area_component_preview.rb b/spec/internal/test/components/previews/view_component/form/text_area_component_preview.rb new file mode 100644 index 00000000..c508d388 --- /dev/null +++ b/spec/internal/test/components/previews/view_component/form/text_area_component_preview.rb @@ -0,0 +1,35 @@ +# frozen_string_literal: true + +require "view_component/form/test_helpers" + +module ViewComponent + module Form + class TextAreaComponentPreview < ViewComponent::Preview + include ViewComponent::Form::TestHelpers + + def default + @object = User.new + + # TODO: maybe stop passing object_name to components since it is accessing from form_builder (delegate in BaseComponent) + render_f ViewComponent::Form::TextAreaComponent, :first_name + end + + def with_value + @object = User.new(first_name: "John\John") + + render_f ViewComponent::Form::TextAreaComponent, :first_name + end + + + private + + def render_f(component_klass, *args, **options) + options[:object] ||= @object + + builder = instanciate_form_builder(options[:object]) + + render component_klass.new(builder, builder.object_name, *args, options) + end + end + end +end diff --git a/spec/internal/test/components/previews/view_component/form/text_field_component_preview.rb b/spec/internal/test/components/previews/view_component/form/text_field_component_preview.rb new file mode 100644 index 00000000..c51f2052 --- /dev/null +++ b/spec/internal/test/components/previews/view_component/form/text_field_component_preview.rb @@ -0,0 +1,35 @@ +# frozen_string_literal: true + +require "view_component/form/test_helpers" + +module ViewComponent + module Form + class TextFieldComponentPreview < ViewComponent::Preview + include ViewComponent::Form::TestHelpers + + def default + @object = User.new + + # TODO: maybe stop passing object_name to components since it is accessing from form_builder (delegate in BaseComponent) + render_f ViewComponent::Form::TextFieldComponent, :first_name + end + + def with_value + @object = User.new(first_name: "John") + + render_f ViewComponent::Form::TextFieldComponent, :first_name + end + + + private + + def render_f(component_klass, *args, **options) + options[:object] ||= @object + + builder = instanciate_form_builder(options[:object]) + + render component_klass.new(builder, builder.object_name, *args, options) + end + end + end +end