`eager_load` performs a single query using a `LEFT OUTER JOIN` to load
the associations. Loading the associations in a join can result in many
rows that contain redundant data and it performs poorly at scale.
With `includes` a separate query is performed for each association,
unless a join is required by conditions.
Co-authored-by: Rafael Mendonça França <rafael@franca.dev>
Since `ActionText::Content` wraps an `ActionText::Fragment`, and
`ActionText::Fragment` wraps a `Nokogiri::XML::DocumentFragment`, then
`ActionText::Content` should be able to rely on the newer Ruby pattern
matching introduced by [nokogiri@1.16.0][] (mainly the
[DocumentFragment#deconstruct][] method):
```ruby
content = ActionText::Content.new <<~HTML
<h1>Hello, world</h1>
<div>The body</div>
HTML
content => [h1, div]
assert_pattern { h1 => { content: "Hello, world" } }
assert_pattern { div => { content: "The body" } }
```
The implementation change relies on delegating from `Content` to
`Fragment`, and from `Fragment` to `DocumentFragment#elements` (to
deliberately exclude text nodes).
[nokogiri@1.16.0]: https://nokogiri.org/CHANGELOG.html?h=pattern
[DocumentFragment#deconstruct]: https://nokogiri.org/rdoc/Nokogiri/XML/DocumentFragment.html?h=deconstruct#method-i-deconstruct
actiontext.js is compiled as ESM bundle instead of UMD bundle.
This leads to issues when trying to use ActionText with sprockets because the ESM bundle declares variables like they are scoped to the file but sprockets will see them as scoped globally.
This is a problem, in particular, if you want to mix actiontext with
turbo-rails.
The problem got introduced in https://github.com/rails/rails/pull/46447.
I traced valid compilation back to
https://github.com/rails/rails/pull/42895.
This commit mimic changes made in
https://github.com/rails/rails/pull/42895 to ActiveStorage:
Retains app/assets/javascripts/actiontext.js as a UMD package for backwards compatibility with
bundling in the asset pipeline, but also adds app/assets/javascripts/actiontext.esm.js for use
with ESM via importmap in the browser.
When Trix was [updated][1] from 1.3.1 to 2.0.4, the ESM bundle of 2.0.4
was used instead of the UMD bundle (the vendored 1.3.1 file used the
UMD bundle). This leads to issues when trying to use Trix with sprockets
because the ESM bundle declares variables like they are scoped to the
file but sprockets will see them as scoped globally.
This commit fixes the issue by replacing the Trix ESM bundle with the
UMD bundle (and upgrades it from 2.0.4 to 2.0.7). Additionally, a Rake
task has been added similar to one previously [added][2] to the guides
for automatic vendoring using Importmap::Packager.
[1]: fab1b522cd11696c7330028fcc7bf25a8a109f5f
[2]: a42863f514e726b864f60ad10e79002fe2b39f5a
which were being set to the HTML4 defaults before the sanitizer
configuration could be applied.
Also, backfill some light tests for sanitization.
Related to #48644
There is a new [Trix.js][] release, bumping the version from `1.3.1` to
`2.0.4`.
Applications that consume Action Text through the `@rails/actiontext`
npm package can manage their own Trix dependency version.
Similarly, Importmaps users can `pin "trix", to: "..."` to a CDN serving
`2.0.4`.
For the sake of applications that depend on Trix through the
`action_text` gem, this commit updates the pre-bundled JS and CSS code.
These changes were generated by executing the following:
```sh
cd actiontext
yarn build
cp ../node_modules/trix/dist/trix.css app/assets/stylesheets/trix.css
cp ../node_modules/trix/dist/trix.esm.js app/assets/javascripts/trix.js
```
[Trix.js]: https://trix-editor.org
[v2.0.4]: https://github.com/basecamp/trix/releases/tag/v2.0.4
When a host is not specified for an `ActionController::Renderer`'s env,
the host and related options will now be derived from the routes'
`default_url_options` and `ActionDispatch::Http::URL.secure_protocol`.
For example, with:
```ruby
Rails.application.default_url_options = { host: "rubyonrails.org" }
Rails.application.config.force_ssl = true
```
Before:
```ruby
ApplicationController.renderer.render inline: "<%= blog_url %>"
# => "http://example.org/blog"
```
After:
```ruby
ApplicationController.renderer.render inline: "<%= blog_url %>"
# => "https://rubyonrails.org/blog"
```
As a consequence, Action Text attachment URLs rendered in a background
job (a la Turbo Streams) will now use `Rails.application.default_url_options`.
Fixes#41795.
Fixeshotwired/turbo-rails#54.
Fixeshotwired/turbo-rails#155.
When System Tests call `fill_in_rich_text_area`, they interact with
`<trix-editor>` elements by changing the contents programmatically.
This is unlike how end-users will interact with the element. Overhauling
the test helper to more accurately reflect Real World usage would
require a sizable effort.
With that being said, leaving the `<trix-editor>` with focus after
populating its contents is a minor change that makes it a more genuine
recreation.
Expand the `has_rich_text` signature to accept a `strict_loading:`
value. Forward that value along to the `has_one` declaration made under
the hood. When omitted, `strict_loading:` will be set to the value of
the `strict_loading_by_default` class attribute (false by default).
* Action Text JS should be available via the asset pipeline too
* Main was a module anyway, no need to reference that twice
* Fix rollup references
* Precompile action text JS for asset pipeline
* No JavaScript dependencies needed with the asset pipeline
* Stub Webpacker::Engine to trigger webpack path for testing
* Extract asset paths
* Exercise asset pipeline path
* Terser doesn't do anything useful on this small package
* Make trix directly available to the asset pipeline
* Indirect doesn't carry its worth
* Reminder for development about keeping things in sync for the asset pipeline
* Ensure this isn't turned into undefined while mirroring
* Mirror Trix CSS for asset pipeline
* Add the needed JS include tag automatically under the asset pipeline
* Please RuboCop
* Keep the peer dependency
Even though we also need it explicitly as a dev dependency in order to generate the mirror output for trix.
* Fix test
* Add CHANGELOG entry
Trix's `<trix-editor>` doesn't support the [form][] property like
`<textarea>` or other form fields.
For example, consider the following HTML and event listener:
```html
<form action="/articles" method="post">
<textarea name="content"></textarea>
<button type="submit">Save</button>
</form>
<script>
addEventListener("keydown", ({ key, metaKey, target }) => {
if (target.form && key == "Enter" && (metaKey || ctrlKey)) {
form.requestSubmit()
}
})
</script>
```
The `target` (an instance of `HTMLTextAreaElement` relies on the
[HTMLTextAreaElement.form][] property for access to its associated
`<form>`. While it's usually equivalent to `target.closest("form")`,
that isn't always the case. Declaring a `[form]` attribute with another
`<form>` element's `[id]` value can associate a field to a `<form>` that
is _not an ancestor_. That means that the event listener from above
would continue to work with this HTML:
```html
<textarea name="content" form="new_article"></textarea>
<!-- elsewhere -->
<form id="new_article" action="/articles" method="post">
<button type="submit">Save</button>
</form>
```
Unfortunately, if the `<textarea>` element were replaced with a
`<trix-editor>`, the event listener's reliance on accessing the form as
a property would break, since the `<trix-editor>` custom element doesn't
declare that property. There is currently a pull request
([basecamp/trix#899][]) to add support for accessing the `form` as a
property of the `<trix-editor>` element.
The [feedback][] provided on that pull request suggests that we
implement the `form` property by delegating to the `<input
type="hidden">` element. Currently, `<input type="hidden">` elements
constructed by Action Text helpers cannot declare the `[form]`
attribute.
This commit adds support by special-casing the `options[:form]` key
within `ActionText::TagHelper#rich_text_area_tag`.
[form]: https://developer.mozilla.org/en-US/docs/Web/API/HTMLTextAreaElement#properties
[basecamp/trix#899]: https://github.com/basecamp/trix/pull/899#discussion_r618543357
[feedback]: https://github.com/basecamp/trix/pull/899#discussion_r618543357
Extensible layout
---
Expose how we render the HTML _surrounding_ rich text content as an
extensible `layouts/action_text/contents/_content.html.erb` template to
encourage user-land customizations, while retaining private API control
over how the rich text itself is rendered by moving the
`#render_action_text_content` helper invocation to the
`action_text/contents/_content.html.erb` partial.
Extensible Attachable `#to_attachable_partial_path`
---
When an application declares a canonical partial for a record, there is
no way to override which partial is used when transformed to Rich Text.
For example, a default `Person < ApplicationRecord` instance returns
`"people/person"` from calls to `#to_partial_path`, resulting in the
`app/views/people/_person.html.erb` partial being rendered.
Prior to this change, when encountering an `<action-text-attachment
sgid="...">` element, ActionText retrieved the corresponding
`Attachable` instance (usually an `ActiveRecord::Base` instance) and
transformed it to rich text HTML by rendering the partial that
corresponds to its `#to_partial_path`.
This proposed change instead invokes
`Attachable#to_attachable_partial_path`. By default,
`#to_attachable_partial_path` is an alias for `#to_partial_path`.
Guides
---
Extend the `guides/action_text_overview` document to
describe how to customize these templates, and to better illustrate how
ActionText::Attachable instances are rendered into HTML.
This change introduces a rich text object to make
it easier to confirm it context is existing or not.
If we have a class like below.
class Information < ApplicationRecord
has_rich_text :notes
end
Before:
i = Information.new
i.notes? => NoMethodError
i.notes = "Some sample text"
i.notes.present? => true
After:
i = Information.new
i.notes? => false
i.notes = "Some sample text"
i.notes? => true