Upgrading RailsPress

Guide for upgrading the RailsPress engine between versions.

Quick Upgrade

Terminal
# 1. Update the gem
$ bundle update railspress-engine

# 2. Copy new migrations
$ rails railspress:install:migrations

# 3. Run migrations
$ rails db:migrate

# 4. Restart your server

Step-by-Step Guide

1. Update the Gem

If using a version constraint in your Gemfile:

Gemfile
gem "railspress-engine", "~> 1.0"

Run:

Terminal
$ bundle update railspress-engine

If using a git source:

Gemfile
gem "railspress-engine", git: "https://github.com/aviflombaum/railspress-engine", branch: "main"

2. Copy New Migrations

RailsPress includes a rake task to copy engine migrations to your application:

Terminal
$ rails railspress:install:migrations

This copies any new migrations from the engine to your db/migrate/ folder. Existing migrations are skipped (matched by migration name, not timestamp).

Check what was copied:

Terminal
$ ls -la db/migrate/*railspress*

3. Review Migration Changes

Before running migrations, review them for any data implications:

Terminal
# See pending migrations
$ rails db:migrate:status

# Preview a specific migration
$ cat db/migrate/TIMESTAMP_create_railspress_exports.rb

4. Run Migrations

Terminal
$ rails db:migrate

For production, consider running migrations separately from deployment:

Terminal (Production)
$ RAILS_ENV=production rails db:migrate

5. Check Configuration

New versions may add configuration options. Review the initializer:

config/initializers/railspress.rb
Railspress.configure do |config|
  config.enable_authors
  config.author_class_name = "User"
  config.author_display_method = :name

  config.enable_post_images
end

Check the Configuration guide for new options.

6. Restart Application

Terminal
# Development
$ rails restart

# Production (example with Puma)
$ pumactl restart

Migration Internals

How Engine Migrations Work

RailsPress migrations live in railspress/db/migrate/. When you run railspress:install:migrations, Rails copies them to your app with new timestamps.

Engine migration:

Engine Path
railspress/db/migrate/20241218000001_create_railspress_categories.rb

Becomes in your app:

App Path
db/migrate/20241224123456_create_railspress_categories.railspress.rb

The .railspress suffix tracks the migration origin.

Migration Naming Convention

RailsPress uses a fixed timestamp prefix pattern:

Timestamp Migration
20241218000001 create_railspress_categories
20241218000002 create_railspress_tags
20241218000003 create_railspress_posts
20241218000004 create_railspress_post_tags
20241218000005 create_railspress_imports
20241218000006 create_railspress_exports
20260415000001 create_railspress_api_keys
20260415000002 create_railspress_agent_bootstrap_keys

New migrations increment the suffix (000007, 000008, etc.).

Checking Migration Status

Terminal
# See all migrations and their status
$ rails db:migrate:status

# Filter to RailsPress migrations
$ rails db:migrate:status | grep railspress

Rolling Back

If needed, rollback a specific migration:

Terminal
# Rollback last migration
$ rails db:rollback

# Rollback to specific version
$ rails db:migrate:down VERSION=20241224123456

Troubleshooting

"Migration already exists"

If the rake task reports migrations already exist, they've been copied before. Check:

Terminal
$ ls db/migrate/*railspress*

Schema Mismatch

If your schema differs from expected migrations:

Terminal
# Check current schema
$ rails db:schema:dump
$ cat db/schema.rb | grep railspress

# Compare with engine migrations
$ ls railspress/db/migrate/

Missing Tables

If RailsPress tables are missing:

Terminal
# Re-copy all migrations
$ rails railspress:install:migrations

# Run pending
$ rails db:migrate

Duplicate Migrations

If you have duplicate migrations (same content, different timestamps):

  1. Check which are already run: rails db:migrate:status
  2. Delete the unrun duplicate
  3. If both are run, the second likely failed silently

Latest Release Notes (v1.4.4)

Released: 2026-08-18

RailsPress 1.4.4 is a security hardening release for post and CMS imports. It changes no supported file formats, public APIs, or configuration options, and it requires no migrations or host application code changes.

  • SSRF-safe remote images: remote post header-image downloads now go through the ssrf_filter gem, which the engine installs as a runtime dependency.
  • Remote image destination validation: loopback, private, link-local, reserved, and other unsafe IPv4 and IPv6 destinations are rejected, and redirect responses are no longer followed.
  • Import upload containment: admin uploads are stored under server-generated names, and cleanup canonicalizes its targets before removing files.
  • ZIP image containment: absolute, traversal, and symlinked image references that resolve outside the extraction directory are rejected.
  • Dependency maintenance: the development lockfile moved to the patched rails-html-sanitizer 1.7.1 and json 2.21.2 releases.

See the v1.4.4 release notes or the full CHANGELOG.

Version-Specific Notes

Upgrading to 1.4.4 (from 1.4.3)

RailsPress 1.4.4 hardens post and CMS imports. Admin uploads are stored under server-generated names, and cleanup only removes canonical paths beneath the Rails temporary directory. Image references inside a ZIP must resolve within their extraction directory, so absolute paths, traversal segments, and symlinks that escape it are rejected.

Remote post header images now use ssrf_filter. Public HTTP and HTTPS images still work, but loopback, private, link-local, reserved, and redirecting destinations are rejected. If a feed you import from serves header images through a redirecting URL, update the frontmatter to the final image URL.

Terminal
bundle update railspress-engine

The engine installs ssrf_filter automatically. There are no migrations, initializer changes, or host application code changes.

Upgrading to 1.4.3 (from 1.4.2)

RailsPress 1.4.3 renames the engine's built-in query helpers to rp_search, rp_page, and rp_per_page_count. The admin and JSON API use only these names, which leaves your application free to define its own search scope or to use any pagination gem without relying on gem load order. There are no migrations, initializer changes, or immediately required host application changes.

Terminal
$ bundle update railspress-engine

Migrate direct uses of the old generic names to their rp_ equivalents, or to your application's preferred search and pagination API:

Deprecated Use instead
Railspress::Post.search(q) Railspress::Post.rp_search(q)
.page(params[:page]) .rp_page(params[:page])
Model.per_page_count Model.rp_per_page_count
Compatibility window

The old names are still defined when your model does not already provide them, so existing calls keep working through RailsPress 1.x. They emit deprecation warnings through the :railspress deprecator, which you can configure like any other Rails deprecator via config.active_support.deprecators. They are removed in RailsPress 2.0.

Kaminari and Pagy users

If you previously deferred the RailsPress require so Kaminari's page would win, you can drop that workaround. Remove require: false from the railspress-engine line in your Gemfile and the manual require "railspress" from your initializer.

The built-in title search is also database-agnostic in 1.4.3: it uses adapter-aware Arel instead of PostgreSQL-only ILIKE SQL, so admin search works on SQLite and MySQL too.

Upgrading to 1.4.2 (from 1.4.1)

RailsPress 1.4.2 raises its runtime floors to Rails 8.1.3.1, Lexxy 0.9.29, and image_processing 2.0.3, and it updates CMS helper loading for newer Rails versions. RailsPress owns the Lexxy and image_processing dependencies, so do not add them to your host Gemfile. There are no migrations, initializer changes, or host application code changes.

Terminal
$ bundle update railspress-engine

If Bundler reports a direct Rails version conflict, unlock Rails at the same time:

Terminal
$ bundle update rails railspress-engine

If your application uses Vips, verify every deployed environment before restarting:

Terminal
$ bundle exec ruby -e 'require "vips"; puts Vips::VERSION'
$ vips --version
libvips version requirement

ruby-vips must be 2.2.1+ and native libvips must be 8.13+. Rails 8.1.3.1 refuses to boot with an older libvips because it cannot disable unsafe operations there. Applications that accepted untrusted image uploads while using Vips on Rails earlier than 8.1.3.1 should follow the Rails security advisory, including rotating application and service credentials that may have been exposed.

Upgrading to 1.4.1 (from 1.4.0)

RailsPress 1.4.1 refines installer guidance and documentation only. There are no migrations, configuration, or host importmap changes.

Terminal
$ bundle update railspress-engine

Your existing config/initializers/railspress.rb is untouched by the upgrade. If you want the newly surfaced commented settings (author_scope, enable_post_images, enable_focal_points) as a reference, compare against a freshly generated initializer or see Basic Setup. If your app requests resized or converted images, review Active Storage & Image Variants to confirm an image processor is installed.

Upgrading to 1.4.0 (from 1.3.x)

RailsPress 1.4.0 adopts Lexxy's first stable release (0.9.24) and refreshes its dependency set. There are no migrations or host importmap changes.

Terminal
$ bundle update railspress-engine lexxy

Keep import "railspress" in your host JavaScript entrypoint if you use host-page RailsPress features such as inline editing. No other changes are required.

Upgrading to 1.3.0

This release adds the versioned JSON API and AI-agent onboarding flow, plus new admin key management screens.

Key additions:

  • /railspress/api/v1 endpoints for posts, post imports, categories, tags, and prime handshake.
  • Agent bootstrap token exchange flow (rpb_* to rp_*).
  • Agents & API admin screen at /railspress/admin/api_keys.
  • Two new encrypted key tables: railspress_api_keys and railspress_agent_bootstrap_keys.

Upgrade checklist:

Terminal
$ bundle update railspress-engine
$ rails railspress:install:migrations
$ rails db:migrate

Required API setup:

  1. Configure Active Record Encryption keys in your host app.
  2. Enable API in config/initializers/railspress.rb with config.enable_api.
  3. Set an API actor method/proc (for example config.current_api_actor_method = :current_user).
  4. Create a bootstrap or direct API key from /railspress/admin/api_keys.

Upgrading to 1.2.0 (from 1.0.0+)

This release improved Lexxy dependency and importmap behavior for host apps.

  • Lexxy dependency moved to an open lower bound (>= 0.9.0.beta).
  • Engine-managed importmap and JS entrypoint now handle Lexxy loading.
  • Install generator no longer adds a manual host lexxy importmap pin.
  • Inline editor rendering and rubyzip compatibility fixes were included.
Terminal
$ bundle update railspress-engine lexxy
$ rails railspress:install:migrations
$ rails db:migrate

Upgrading to 1.0.0

New: Blocks (Content Element CMS), Inline Editing, and content transfer

New configuration:

config/initializers/railspress.rb
Railspress.configure do |config|
  config.enable_cms
  config.inline_editing_check = ->(ctx) { ctx.controller.current_user&.admin? }
end

Upgrading to 0.1.x

Initial release. Run full install:

Terminal
$ rails generate railspress:install
$ rails db:migrate

CI/CD Considerations

Automated Upgrades

In CI, ensure migrations run before tests:

.github/workflows/test.yml
- name: Setup database
  run: |
    rails railspress:install:migrations
    rails db:create db:migrate

Production Deployments

For zero-downtime deploys, run migrations before deploying new code if they're additive (new tables, new columns with defaults).

For destructive migrations (removing columns), deploy code first, then migrate.

Deploy Sequence
# Typical deploy sequence
$ git pull origin main
$ bundle install
$ rails railspress:install:migrations
$ rails db:migrate
$ rails assets:precompile
# restart app

Getting Help