Skip to content

Use ActionText::Editor adapter on Rails 8.2+, fall back to monkey-patching on older Rails#778

Draft
jorgemanrubia wants to merge 2 commits intomainfrom
action-text-editor-adapter
Draft

Use ActionText::Editor adapter on Rails 8.2+, fall back to monkey-patching on older Rails#778
jorgemanrubia wants to merge 2 commits intomainfrom
action-text-editor-adapter

Conversation

@jorgemanrubia
Copy link
Member

@jorgemanrubia jorgemanrubia commented Mar 4, 2026

Summary

  • Introduces ActionText::Editor::LexxyEditor for Rails 8.2+, leveraging the new first-class editor adapter API from rails/rails#51238 — no monkey-patching needed on new Rails
  • On Rails 8.0/8.1 where ActionText::Editor is not defined, the existing prepend-based approach is used unchanged (fully transparent fallback)
  • Detection happens at load time via defined?(ActionText::Editor) in lib/lexxy/engine.rb

CI matrix

The USE_RAILS_WITHOUT_ACTION_TEXT_ADAPTER env variable in the Gemfile controls which Rails version is used:

  • Rails 8.1 (USE_RAILS_WITHOUT_ACTION_TEXT_ADAPTER=true) — tests the monkey-patch fallback path
  • Rails main (default) — tests the new adapter path

Both legs run on every PR.

Copilot AI review requested due to automatic review settings March 4, 2026 08:33
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates Lexxy’s Rails integration to use the new ActionText::Editor adapter API on Rails 8.2+ while preserving the existing prepend/monkey-patch approach on Rails 8.0/8.1, and adds CI coverage for both paths.

Changes:

  • Add an ActionText::Editor::LexxyEditor adapter for Rails versions that provide ActionText::Editor.
  • Keep the legacy helper monkey-patching path for Rails 8.0/8.1 when ActionText::Editor is absent.
  • Update CI/Gemfile to run a matrix against Rails 8.1 and Rails main, and configure the dummy app to select the Lexxy editor when supported.

Reviewed changes

Copilot reviewed 7 out of 8 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
test/dummy/config/application.rb Sets config.action_text.editor = :lexxy when the adapter API is available.
lib/lexxy/engine.rb Chooses adapter-vs-legacy integration at load time and registers the editor in Rails 8.2+.
lib/action_text/editor/lexxy_editor.rb Introduces the ActionText editor adapter implementation for Lexxy.
Gemfile Adds an env-controlled Rails dependency to switch between Rails 8.1 and Rails main.
Gemfile.lock Updates lockfile to reflect Rails main and updated dependency set.
.github/workflows/ci.yml Adds a CI matrix leg for Rails 8.1 (legacy path) and Rails main (adapter path).
CLAUDE.md Adds a reference to AGENTS instructions.
AGENTS.md Adds contributor guidance for resolving JS asset merge conflicts.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

…ey-patching on 8.0/8.1

Introduces ActionText::Editor::LexxyEditor for Rails 8.2+ (PR #51238),
which registers Lexxy as a first-class Action Text editor without
monkey-patching. On older Rails where ActionText::Editor is not defined,
the existing prepend-based approach is used unchanged.

CI runs a matrix via USE_RAILS_WITHOUT_ACTION_TEXT_ADAPTER env var:
true = Rails 8.1 (fallback path), unset = Rails main (adapter path).
Gemfile.lock is not committed (gem convention) to avoid lockfile
conflicts between matrix legs. Dev dependencies are pinned with ~>.
@jorgemanrubia jorgemanrubia force-pushed the action-text-editor-adapter branch from c6a4042 to eb5e338 Compare March 4, 2026 08:40
Copilot AI review requested due to automatic review settings March 4, 2026 08:42
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 10 out of 12 changed files in this pull request and generated 1 comment.

Comments suppressed due to low confidence (3)

test/helpers/lexxy/tag_helper_test.rb:8

  • Skipping this whole test class when ActionText::Editor is defined leaves key escaping/serialization behaviors (e.g., preserving HTML entities in the value attribute) untested on the Rails 8.2+ adapter path. Instead of skipping, add equivalent assertions for the adapter path (for example by rendering the configured rich_textarea/editor tag and checking the produced value).
  setup do
    skip "lexxy_rich_textarea_tag is not available when using the ActionText::Editor adapter" if defined?(ActionText::Editor)
  end

Gemfile:29

  • capybara, selenium-webdriver, and cuprite are already declared as development dependencies in lexxy.gemspec. Duplicating them here makes version bumps easy to miss and can cause Bundler resolution conflicts if the constraints diverge—consider keeping these dev deps in only one place (preferably the gemspec, since gemspec is already used).
gem "capybara", "~> 3.0"
gem "selenium-webdriver", "~> 4.0"
gem "cuprite", "~> 0.17"

lib/lexxy/engine.rb:15

  • In the Rails 8.2+ adapter branch, config.lexxy.override_action_text_defaults is never set/used, so the documented default behavior (“override Action Text defaults unless opted out”) becomes a no-op on newer Rails. Consider keeping this option effective on Rails 8.2+ (e.g., default it to true and, when enabled, set config.action_text.editor = :lexxy and/or ensure the explicit lexxy_* helpers are still available).
    if defined?(ActionText::Editor)
      # Rails 8.2+: use the first-class editor adapter API
      require_relative "../action_text/editor/lexxy_editor"

      initializer "lexxy.action_text_editor", before: "action_text.editors" do |app|

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.


class Editor::LexxyEditor::Tag < Editor::Tag
def render_in(view_context, ...)
options[:value] = "<div>#{options[:value]}</div>" if options[:value].present?
Copy link

Copilot AI Mar 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

options[:value] here may be an html_safe string (there are legacy tests that rely on stripping html_safe to ensure attribute-escaping preserves entities like &lt; in code blocks). Before wrapping/assigning, coerce the value to a plain String (removing html_safe) so the rendered value attribute can’t end up unescaped / double-interpreted by the browser.

Suggested change
options[:value] = "<div>#{options[:value]}</div>" if options[:value].present?
if options[:value].present?
value = options[:value].to_s
options[:value] = "<div>#{value}</div>"
end

Copilot uses AI. Check for mistakes.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In #724 we removed the wrapping <div> to prevent collisions with ImageGalleries (#716). While Copilot is wrong since to_s will not coerce a SafeBuffer to a string, it's important to ensure removal of html_safe from the value (we used to_str in #749).

@jorgemanrubia jorgemanrubia marked this pull request as draft March 4, 2026 09:01
@jorgemanrubia
Copy link
Member Author

I need to get something tweaked in Rails before getting this in place!

@jorgemanrubia
Copy link
Member Author

jorgemanrubia commented Mar 4, 2026

The adapter path currently fails the system tests because Editor::Tag#render_in renders an empty editor element — the block passed to rich_textarea_tag (which contains the <lexxy-prompt> elements) is dropped entirely.

The fix is in rails/rails#56926:

  • Editor::Tag now stores a block given to editor_tag and passes it to content_tag in render_in, so the block renders as DOM children of the editor element.
  • rich_textarea_tag passes the block to editor_tag instead of capturing it as the initial value.
  • Value and block children are independent: value flows into the editor's content binding (hidden input for Trix, value attribute for custom editors), while the block renders as inner DOM children.

This PR will be unblocked once that lands in Rails.

@jorgemanrubia
Copy link
Member Author

Waiting on rails/rails#56926

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants