BREAKING CHANGE: has_folio_tiptap? has been changed from a class method to an instance method.
Before (7.2.*):
Folio::Page.has_folio_tiptap? # class methodAfter (7.3.0):
page.has_folio_tiptap? # instance methodAction required:
- Update all code that calls
has_folio_tiptap?as a class method to use it as an instance method - Update test stubs from
Folio::Page.stub(:has_folio_tiptap?, true)topage.stub(:has_folio_tiptap?, true) - Search your codebase for
\.has_folio_tiptap\?andhas_folio_tiptap\?to find all usages
BREAKING CHANGE: tiptap_config and tiptap_autosave_enabled? methods on models now accept an optional attribute_name: keyword argument to scope configuration per Tiptap attribute.
Before (7.2.*):
class MyApp::Page < Folio::ApplicationRecord
include Folio::Tiptap::Model
def tiptap_config
Folio::Tiptap::Config.new(...)
end
endAfter (7.3.0):
class MyApp::Page < Folio::ApplicationRecord
include Folio::Tiptap::Model
def tiptap_config(attribute_name: nil)
# attribute_name can be used to return different configs per field
# When nil, return default/global config
Folio::Tiptap::Config.new(...)
end
endAction required:
-
Update all model overrides that define
tiptap_configto acceptattribute_name: nilparameter:# Old def tiptap_config ... end # New def tiptap_config(attribute_name: nil) ... end
-
If you have custom
tiptap_autosave_enabled?overrides, update them similarly:def tiptap_autosave_enabled?(attribute_name: nil) tiptap_config(attribute_name: attribute_name)&.autosave == true end
-
Search your codebase for
def tiptap_configanddef tiptap_autosave_enabled?to find all overrides
Note: The default implementation in Folio::Tiptap::Model already handles the new signature. This change only affects models that override these methods.
BREAKING CHANGE: TipTap node configuration structure has been flattened. You must update all node class definitions.
Before (7.0.0):
# app/models/my_app/tiptap/node/contents/text.rb
tiptap_node structure: {
content: :rich_text,
}, tiptap_config: {
toolbar: {
icon: "content_text",
slot: "after_layouts",
},
}After (7.1.0):
# app/models/my_app/tiptap/node/contents/text.rb
tiptap_node structure: {
content: :rich_text,
}, tiptap_config: {
icon: "content_text", # Flattened from toolbar.icon
toolbar_slot: "after_layouts", # Flattened from toolbar.slot
}Node groups allow organizing nodes into dropdown menus. This is an optional feature:
1. Add node_groups to config (optional):
# app/models/my_app.rb
def self.default_tiptap_config
::Folio::Tiptap::Config.new(
node_names: [...],
node_groups: [ # Optional - new feature
{
key: "content",
title: { cs: "Obsah", en: "Content" },
icon: "content",
toolbar_slot: "after_layouts", # Optional - controls toolbar position
},
],
)
end2. Assign nodes to groups:
# app/models/my_app/tiptap/node/contents/text.rb
tiptap_node structure: {
content: :rich_text,
}, tiptap_config: {
icon: "content_text",
toolbar_slot: "after_layouts", # Optional - for individual button
group: "content", # Optional - for dropdown menu
}3. Independent group and toolbar_slot:
groupandtoolbar_slotare independent properties- Nodes can have both and will appear in both places:
- In the group dropdown menu (if they have
group) - As individual toolbar buttons (if they have
toolbar_slot)
- In the group dropdown menu (if they have
Action required:
- Search your codebase for
tiptap_config: { toolbar: {and flatten to direct properties - Update all node class definitions:
toolbar: { icon: "..." }→icon: "..."toolbar: { slot: "..." }→toolbar_slot: "..."
- If using node groups, add
group: "..."to node configs - Update TypeScript types if you have custom TipTap extensions:
- Update property access from
node.config.toolbar.icontonode.config.icon - Update property access from
node.config.toolbar.slottonode.config.toolbar_slot
- Update property access from
See docs/tiptap.md for complete documentation and examples.
- Rails upgraded to 8.0.1 - Review Rails 8.0 upgrade guide and ensure all dependencies are compatible
- Update your Gemfile to use Rails 8.0.1
- Run
bundle update railsand resolve any dependency conflicts
- Folio::File hash_id -> slug: Run the migration to rename
hash_idcolumn tosluginfolio_filestable# Migration is included: 20251031141402_change_files_hash_id_to_slug.rb # Update any code referencing Folio::File#hash_id to use #slug instead
- Review and run all new migrations from Folio 6.x to 7.0.0
The following Cells have been refactored to ViewComponents. Update your code:
Folio::Console::Form::HeaderCell→Folio::Console::Form::HeaderComponentFolio::PublishableHintCell→Folio::Publishable::HintComponent
Action required: Search your codebase for references to these cells and update:
# Old
cell("folio/console/form/header", ...)
# New
render(Folio::Console::Form::HeaderComponent.new(...))- Default
showaction redirects toedit: If your controllers rely on the defaultshowaction, you must explicitly define it:Controllers usingdef show # Your custom show logic here end
superinshowwill now redirect toeditinstead.
- AjaxInputComponent API response format changed: Update any custom API endpoints used by
Folio::Console::Ui::AjaxInputComponent# Old format { value: new_value } # New format { name => new_value } # where name is the field name
- Devise modules: Default
devise_modulesmoved to Folio config. If you need custom modules, configure them in your Folio initializer:Rails.application.config.folio_devise_modules = %i[database_authenticatable ...]
- Uppy File Uploader replaces legacy upload components: If you have custom upload code using the old system, migrate to Uppy
- Review file upload forms and ensure they work with the new Uppy-based system
- Check that file replacement functionality still works as expected
- Autocomplete redone without jQuery UI: If you have custom autocomplete code relying on jQuery UI, update it to use the new implementation
- Custom autocomplete endpoints should continue to work, but verify behavior
- TipTap is now the primary rich text editor: If migrating from Redactor or other editors, see docs/tiptap.md for migration guide
- Review all rich text fields and ensure they work with TipTap
- Update any custom TipTap extensions or configurations
- Complete rewrite of embed functionality: If using the old embed system, migrate to the new
EmbedInputandFolio::Embed::BoxComponent - See docs/embed.md for details on the new implementation
- Update models to include
Folio::Embed::Validationconcern if needed
- Update test helpers if they reference deprecated Cells
- Review console controller tests for
showaction behavior changes - Update API tests for
AjaxInputComponentresponse format changes
- Replace
include Folio::HasSanitizedFieldswithinclude Folio::HtmlSanitization::Modelon yourApplicationRecord. - Sanitizer sanitizes all strings/texts and JSON containing strings/texts by default.
- Go through all of your models and pick the attributes that may contain HTML. Should such a model exist, define a
folio_html_sanitization_configmethod (overriding the concern default) with the following syntax
def folio_html_sanitization_config { enabled: true, attributes: { attribute_1: :unsafe_html, attribute_2: :rich_text, attribute_3: -> (value) { custom_sanitization_handler(value) }, }, } end
- The following values are supported:
:unsafe_html- ignore the attribute, don't sanitize at all:rich_text- keep safe HTML tags and attributes viaRails::HTML5::SafeListSanitizer- proc, i.e.
-> (value) { custom_sanitization_handler(value) }- pass a proc which will be given value of attribute
- Attributes not defined in the
:attributeshash are stripped of all HTML usingLoofah - You can disable the sanitization for your model by setting
{ enabled: false } - Example override for
Folio::EmailTemplateas thebody_html_*can differ across projects:
def folio_html_sanitization_config attributes_config = {} attribute_names.each do |attribute_name| if attribute_name.starts_with?("body_html") attributes_config[attribute_name.to_sym] = :rich_text end end { enabled: true, attributes: attributes_config, } end
- Go through all of your models and pick the attributes that may contain HTML. Should such a model exist, define a