README.md in actionview-component-1.13.0 vs README.md in actionview-component-1.14.0

- old
+ new

@@ -1,14 +1,28 @@ -_Note: This gem is in the process of a name / API change, see https://github.com/github/actionview-component/issues/206_ +# ViewComponent +A view component framework for Rails. -_You are viewing the README for the development version of ActionView::Component. If you are using the current release version you can find the README at https://github.com/github/actionview-component/blob/v1.11.1/README.md_ +**Current Status**: Used in production at GitHub. Because of this, all changes will be thoroughly vetted, which could slow down the process of contributing. We will do our best to actively communicate status of pull requests with any contributors. If you have any substantial changes that you would like to make, it would be great to first [open an issue](http://github.com/github/actionview-component/issues/new) to discuss them with us. -# ActionView::Component -`ActionView::Component` is a framework for building view components in Rails. +## Migration in progress -**Current Status**: Used in production at GitHub. Because of this, all changes will be thoroughly vetted, which could slow down the process of contributing. We will do our best to actively communicate status of pull requests with any contributors. If you have any substantial changes that you would like to make, it would be great to first [open an issue](http://github.com/github/actionview-component/issues/new) to discuss them with us. +This gem is in the process of a name / API change from `ActionView::Component` to `ViewComponent`, see https://github.com/github/actionview-component/issues/206. +### What's changing in the migration + +1. `ActionView::Component::Base` is now `ViewComponent::Base`. +1. Components can only be rendered with `render(MyComponent.new)` syntax. +1. Validations are no longer supported by default. + +### How to migrate to ViewComponent + +1. In `application.rb`, require `view_component/engine` +1. Update components to inherit from `ViewComponent::Base`. +1. Update component tests to inherit from `ViewComponent::TestCase`. +1. Update component previews to inherit from `ViewComponent::Preview`. +1. Include `ViewComponent::TestHelpers` in your test suite. + ## Roadmap Support for third-party component frameworks was merged into Rails `6.1.0.alpha` in https://github.com/rails/rails/pull/36388 and https://github.com/rails/rails/pull/37919. Our goal with this project is to provide a first-class component framework for this new capability in Rails. This gem includes a backport of those changes for Rails `5.0.0` through `6.1.0.alpha`. @@ -34,18 +48,18 @@ ``` In `config/application.rb`, add: ```bash -require "action_view/component/railtie" +require "view_component/engine" ``` ## Guide ### What are components? -`ActionView::Component`s are Ruby classes that are used to render views. They take data as input and return output-safe HTML. Think of them as an evolution of the presenter/decorator/view model pattern, inspired by [React Components](https://reactjs.org/docs/react-component.html). +`ViewComponent`s are Ruby classes that are used to render views. They take data as input and return output-safe HTML. Think of them as an evolution of the presenter/decorator/view model pattern, inspired by [React Components](https://reactjs.org/docs/react-component.html). ### Why components? In working on views in the Rails monolith at GitHub (which has over 3700 templates), we have run into several key pain points: @@ -67,15 +81,15 @@ ### What are the benefits? #### Testing -`ActionView::Component` allows views to be unit-tested. In the main GitHub codebase, our unit tests run in around 25ms/test, vs. ~6s/test for integration tests. +`ViewComponent` allows views to be unit-tested. In the main GitHub codebase, our unit tests run in around 25ms/test, vs. ~6s/test for integration tests. #### Code Coverage -`ActionView::Component` is at least partially compatible with code coverage tools. We’ve seen some success with SimpleCov. +`ViewComponent` is at least partially compatible with code coverage tools. We’ve seen some success with SimpleCov. #### Data flow By clearly defining the context necessary to render a component, we’ve found them to be easier to reuse than partials. @@ -85,23 +99,21 @@ ### Building components #### Conventions -Components are subclasses of `ActionView::Component::Base` and live in `app/components`. You may wish to create an `ApplicationComponent` that is a subclass of `ActionView::Component::Base` and inherit from that instead. +Components are subclasses of `ViewComponent::Base` and live in `app/components`. You may wish to create an `ApplicationComponent` that is a subclass of `ViewComponent::Base` and inherit from that instead. Component class names end in -`Component`. Component module names are plural, as they are for controllers. (`Users::AvatarComponent`) -Components support ActiveModel validations. Components are validated after initialization, but before rendering. +Content passed to a `ViewComponent` as a block is captured and assigned to the `content` accessor. -Content passed to an `ActionView::Component` as a block is captured and assigned to the `content` accessor. - #### Quick start -Use the component generator to create a new `ActionView::Component`. +Use the component generator to create a new `ViewComponent`. The generator accepts the component name and the list of accepted properties as arguments: ```bash bin/rails generate component Example title content @@ -109,11 +121,11 @@ create test/components/example_component_test.rb create app/components/example_component.rb create app/components/example_component.html.erb ``` -`ActionView::Component` includes template generators for the `erb`, `haml`, and `slim` template engines and will use the template engine specified in your Rails config (`config.generators.template_engine`) by default. +`ViewComponent` includes template generators for the `erb`, `haml`, and `slim` template engines and will use the template engine specified in your Rails config (`config.generators.template_engine`) by default. If you want to override this behavior, you can pass the template engine as an option to the generator: ```bash bin/rails generate component Example title content --template-engine slim @@ -123,17 +135,15 @@ create app/components/example_component.html.slim ``` #### Implementation -An `ActionView::Component` is a Ruby file and corresponding template file (in any format supported by Rails) with the same base name: +A `ViewComponent` is a Ruby file and corresponding template file (in any format supported by Rails) with the same base name: `app/components/test_component.rb`: ```ruby -class TestComponent < ActionView::Component::Base - validates :content, :title, presence: true - +class TestComponent < ViewComponent::Base def initialize(title:) @title = title end private @@ -159,33 +169,17 @@ ```html <span title="my title">Hello, World!</span> ``` -#### Error case - -If the component is rendered with a blank title: - -```erb -<%= render(TestComponent.new(title: "")) do %> - Hello, World! -<% end %> -``` - -An error will be raised: - -`ActiveModel::ValidationError: Validation failed: Title can't be blank` - #### Content Areas A component can declare additional content areas to be rendered in the component. For example: `app/components/modal_component.rb`: ```ruby -class ModalComponent < ActionView::Component::Base - validates :user, :header, :body, presence: true - +class ModalComponent < ViewComponent::Base with_content_areas :header, :body def initialize(user:) @user = user end @@ -229,13 +223,11 @@ ##### Required render argument optionally overridden or wrapped by a named block `app/components/modal_component.rb`: ```ruby -class ModalComponent < ActionView::Component::Base - validates :header, :body, presence: true - +class ModalComponent < ViewComponent::Base with_content_areas :header, :body def initialize(header:) @header = header end @@ -255,13 +247,11 @@ ##### Required argument passed by render argument or by named block `app/components/modal_component.rb`: ```ruby -class ModalComponent < ActionView::Component::Base - validates :header, :body, presence: true - +class ModalComponent < ViewComponent::Base with_content_areas :header, :body def initialize(header: nil) @header = header end @@ -291,13 +281,11 @@ ##### Optional argument passed by render argument, by named block, or neither `app/components/modal_component.rb`: ```ruby -class ModalComponent < ActionView::Component::Base - validates :body, presence: true - +class ModalComponent < ViewComponent::Base with_content_areas :header, :body def initialize(header: nil) @header = header end @@ -370,11 +358,11 @@ The `#render?` hook allows you to move this logic into the Ruby class, leaving your views more readable and declarative in style: ```ruby # app/components/confirm_email_component.rb -class ConfirmEmailComponent < ActionView::Component::Base +class ConfirmEmailComponent < ViewComponent::Base def initialize(user:) @user = user end def render? @@ -400,13 +388,13 @@ ### Testing Components are unit tested directly. The `render_inline` test helper is compatible with Capybara matchers, allowing us to test the component above as: ```ruby -require "action_view/component/test_case" +require "view_component/test_case" -class MyComponentTest < ActionView::Component::TestCase +class MyComponentTest < ViewComponent::TestCase test "render component" do render_inline(TestComponent.new(title: "my title")) { "Hello, World!" } assert_selector("span[title='my title']", "Hello, World!") end @@ -428,19 +416,19 @@ end end ``` ### Previewing Components -`ActionView::Component::Preview` provides a way to see how components look by visiting a special URL that renders them. +`ViewComponent::Preview` provides a way to see how components look by visiting a special URL that renders them. In the previous example, the preview class for `TestComponent` would be called `TestComponentPreview` and located in `test/components/previews/test_component_preview.rb`. To see the preview of the component with a given title, implement a method that renders the component. You can define as many examples as you want: ```ruby # test/components/previews/test_component_preview.rb -class TestComponentPreview < ActionView::Component::Preview +class TestComponentPreview < ViewComponent::Preview def with_default_title render(TestComponent.new(title: "Test component default")) end def with_long_title @@ -455,11 +443,11 @@ Previews use the application layout by default, but you can also use other layouts from your app: ```ruby # test/components/previews/test_component_preview.rb -class TestComponentPreview < ActionView::Component::Preview +class TestComponentPreview < ViewComponent::Preview layout "admin" ... end ``` @@ -486,17 +474,17 @@ If you're using RSpec, you can configure component specs to have access to test helpers. Add the following to `spec/rails_helper.rb`: ```ruby -require "action_view/component/test_helpers" +require "view_component/test_helpers" RSpec.configure do |config| # ... # Ensure that the test helpers are available in component specs - config.include ActionView::Component::TestHelpers, type: :component + config.include ViewComponent::TestHelpers, type: :component end ``` Specs created by the generator should now have access to test helpers like `render_inline`. @@ -506,11 +494,11 @@ config.action_view_component.preview_path = "#{Rails.root}/spec/components/previews" ``` ### Initializer requirement -ActionView::Component requires the presence of an `initialize` method in each component. +`ViewComponent` requires the presence of an `initialize` method in each component. ## Frequently Asked Questions ### Can I use other templating languages besides ERB? @@ -520,10 +508,10 @@ Inline templates have been removed (for now) due to concerns raised by [@soutaro](https://github.com/soutaro) regarding compatibility with the type systems being developed for Ruby 3. ### Isn't this just like X library? -`ActionView::Component` is far from a novel idea! Popular implementations of view components in Ruby include, but are not limited to: +`ViewComponent` is far from a novel idea! Popular implementations of view components in Ruby include, but are not limited to: - [trailblazer/cells](https://github.com/trailblazer/cells) - [dry-rb/dry-view](https://github.com/dry-rb/dry-view) - [komposable/komponent](https://github.com/komposable/komponent) - [activeadmin/arbre](https://github.com/activeadmin/arbre)