studio-engine 0.92.0 → 0.92.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +23 -0
- data/db/migrate/20261006120001_ensure_error_logs_table.rb +66 -0
- data/db/migrate/20261006120002_ensure_theme_settings_table.rb +63 -0
- data/db/migrate/20261006120003_ensure_image_caches_table.rb +63 -0
- data/lib/studio/engine.rb +7 -0
- data/lib/studio/host_schema.rb +144 -0
- data/lib/studio/version.rb +1 -1
- data/lib/studio.rb +7 -0
- metadata +6 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 33eb1f55bd158e9d6c588739db65fbef1a5ba8b707b1e0c0469b539d3e6643fa
|
|
4
|
+
data.tar.gz: f3c5845a77976e33edc87e04da3de0e08fd890203f901352a3b419ee3f58f489
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: ec17e35ab084a92080f6bc9fa9565cd5ca6a2f71c8f9f75311ef32f1955c140d9391ed34fa78adcffa8fb84892e043074cf5d7cd89b9f09418edf4af72007b9c
|
|
7
|
+
data.tar.gz: 411eed22d765f4fa318805debbd117353b38f6d518d69b411673bca76d73375812d9f0baa36f69fa1ab25f55976302fe8d37f9ffe5231a4fbd9bfc4002e1b5e8
|
data/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,29 @@ The format is [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). This pro
|
|
|
4
4
|
|
|
5
5
|
## Unreleased
|
|
6
6
|
|
|
7
|
+
## 0.92.1 — 2026-10-07
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- **The engine owns `error_logs`, `theme_settings` and `image_caches`.** Three
|
|
12
|
+
migrations (`ensure_error_logs_table`, `ensure_theme_settings_table`,
|
|
13
|
+
`ensure_image_caches_table`) create each table when it is absent and, on an app
|
|
14
|
+
that already has it, add only the engine columns it lacks, as nullable columns;
|
|
15
|
+
nothing is altered or dropped and no index is added. Adopt with
|
|
16
|
+
`bin/rails studio_engine:install:migrations` and `bin/rails db:migrate`; the
|
|
17
|
+
release's lock bump does both. Hosts no longer copy these tables from
|
|
18
|
+
`docs/NEW_APP_SETUP.md`.
|
|
19
|
+
- **A boot check names a missing engine column** (`Studio::HostSchema`). It
|
|
20
|
+
raises `Studio::HostSchemaError` in development and test, and logs (and reports
|
|
21
|
+
to Sentry) in production; `Studio.host_schema_check = :raise | :log | false`
|
|
22
|
+
overrides. Extra host columns are never reported, and rake tasks skip it.
|
|
23
|
+
|
|
24
|
+
### Fixed
|
|
25
|
+
|
|
26
|
+
- **A theme save no longer raises on apps without `theme_settings.slug`**
|
|
27
|
+
(Cyvasse, McRitchie Industries and Moms App): `ensure_theme_settings_table`
|
|
28
|
+
adds the column `ThemeSetting` writes on every save.
|
|
29
|
+
|
|
7
30
|
## 0.92.0 — 2026-10-06
|
|
8
31
|
|
|
9
32
|
### Added
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# The engine owns the shape of `error_logs`: ErrorLog and the /error_logs pages
|
|
2
|
+
# write and read the columns below on every host.
|
|
3
|
+
#
|
|
4
|
+
# A host that predates this migration already has the table, built by its own
|
|
5
|
+
# migration from docs/NEW_APP_SETUP.md, and the hosts disagree on details (turf
|
|
6
|
+
# has NOT NULL on message, an index on created_at and no unique index on slug).
|
|
7
|
+
# So the migration is a baseline, not a rebuild:
|
|
8
|
+
#
|
|
9
|
+
# - no table: create it in the engine's shape, with its indexes;
|
|
10
|
+
# - a table: add any engine column it lacks, as a plain nullable column, and
|
|
11
|
+
# touch nothing else. No column is changed or dropped, no constraint is
|
|
12
|
+
# tightened and no index is added, because a host's indexes and NOT NULLs
|
|
13
|
+
# are its own, and a unique index built during a release-phase migrate can
|
|
14
|
+
# fail on existing rows or lock a large table.
|
|
15
|
+
#
|
|
16
|
+
# On every consumer that existed when this shipped, the second branch adds
|
|
17
|
+
# nothing. Studio::HostSchema checks the same columns at boot.
|
|
18
|
+
class EnsureErrorLogsTable < ActiveRecord::Migration[7.2]
|
|
19
|
+
def up
|
|
20
|
+
unless table_exists?(:error_logs)
|
|
21
|
+
create_table :error_logs do |t|
|
|
22
|
+
t.string :slug
|
|
23
|
+
t.text :message
|
|
24
|
+
t.text :inspect
|
|
25
|
+
t.text :backtrace
|
|
26
|
+
t.string :target_type
|
|
27
|
+
t.bigint :target_id
|
|
28
|
+
t.string :target_name
|
|
29
|
+
t.string :parent_type
|
|
30
|
+
t.bigint :parent_id
|
|
31
|
+
t.string :parent_name
|
|
32
|
+
|
|
33
|
+
t.timestamps
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
add_index :error_logs, :slug, unique: true
|
|
37
|
+
add_index :error_logs, %i[target_type target_id]
|
|
38
|
+
add_index :error_logs, %i[parent_type parent_id]
|
|
39
|
+
return
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
add_column :error_logs, :slug, :string, if_not_exists: true
|
|
43
|
+
add_column :error_logs, :message, :text, if_not_exists: true
|
|
44
|
+
add_column :error_logs, :inspect, :text, if_not_exists: true
|
|
45
|
+
add_column :error_logs, :backtrace, :text, if_not_exists: true
|
|
46
|
+
add_column :error_logs, :target_type, :string, if_not_exists: true
|
|
47
|
+
add_column :error_logs, :target_id, :bigint, if_not_exists: true
|
|
48
|
+
add_column :error_logs, :target_name, :string, if_not_exists: true
|
|
49
|
+
add_column :error_logs, :parent_type, :string, if_not_exists: true
|
|
50
|
+
add_column :error_logs, :parent_id, :bigint, if_not_exists: true
|
|
51
|
+
add_column :error_logs, :parent_name, :string, if_not_exists: true
|
|
52
|
+
add_column :error_logs, :created_at, :datetime, if_not_exists: true
|
|
53
|
+
add_column :error_logs, :updated_at, :datetime, if_not_exists: true
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# The migration records nothing about whether it created the table or found
|
|
57
|
+
# it, so a down cannot tell the engine's table from the host's own, and
|
|
58
|
+
# dropping it would destroy the host's error history. It refuses instead.
|
|
59
|
+
def down
|
|
60
|
+
return unless table_exists?(:error_logs)
|
|
61
|
+
|
|
62
|
+
raise ActiveRecord::IrreversibleMigration,
|
|
63
|
+
"EnsureErrorLogsTable cannot tell whether it created error_logs or found the host's own; " \
|
|
64
|
+
"drop the table by hand if this app truly owns none of its rows."
|
|
65
|
+
end
|
|
66
|
+
end
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# The engine owns the shape of `theme_settings`: ThemeSetting and /admin/theme
|
|
2
|
+
# write the columns below on every host.
|
|
3
|
+
#
|
|
4
|
+
# `slug` is the column this migration exists for. ThemeSetting includes
|
|
5
|
+
# Sluggable, whose before_save writes `slug` on every save, and the setup doc's
|
|
6
|
+
# hand-copied migration omitted it, so a theme save raises on any host built
|
|
7
|
+
# from that doc (cyvasse, mcritchie-industries and moms-app when this shipped).
|
|
8
|
+
# The slug is "theme-<app_name>", derived on save; existing rows keep a NULL
|
|
9
|
+
# slug until their next save, and nothing looks a theme up by slug.
|
|
10
|
+
#
|
|
11
|
+
# A baseline, not a rebuild:
|
|
12
|
+
#
|
|
13
|
+
# - no table: create it in the engine's shape, with its unique app_name index;
|
|
14
|
+
# - a table: add any engine column it lacks, as a plain nullable column, and
|
|
15
|
+
# touch nothing else. No column is changed or dropped, no constraint is
|
|
16
|
+
# tightened and no index is added.
|
|
17
|
+
#
|
|
18
|
+
# Studio::HostSchema checks the same columns at boot.
|
|
19
|
+
class EnsureThemeSettingsTable < ActiveRecord::Migration[7.2]
|
|
20
|
+
def up
|
|
21
|
+
unless table_exists?(:theme_settings)
|
|
22
|
+
create_table :theme_settings do |t|
|
|
23
|
+
t.string :app_name, null: false
|
|
24
|
+
t.string :slug
|
|
25
|
+
t.string :primary
|
|
26
|
+
t.string :dark
|
|
27
|
+
t.string :light
|
|
28
|
+
t.string :accent1
|
|
29
|
+
t.string :accent2
|
|
30
|
+
t.string :warning
|
|
31
|
+
t.string :danger
|
|
32
|
+
|
|
33
|
+
t.timestamps
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
add_index :theme_settings, :app_name, unique: true
|
|
37
|
+
return
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
add_column :theme_settings, :app_name, :string, if_not_exists: true
|
|
41
|
+
add_column :theme_settings, :slug, :string, if_not_exists: true
|
|
42
|
+
add_column :theme_settings, :primary, :string, if_not_exists: true
|
|
43
|
+
add_column :theme_settings, :dark, :string, if_not_exists: true
|
|
44
|
+
add_column :theme_settings, :light, :string, if_not_exists: true
|
|
45
|
+
add_column :theme_settings, :accent1, :string, if_not_exists: true
|
|
46
|
+
add_column :theme_settings, :accent2, :string, if_not_exists: true
|
|
47
|
+
add_column :theme_settings, :warning, :string, if_not_exists: true
|
|
48
|
+
add_column :theme_settings, :danger, :string, if_not_exists: true
|
|
49
|
+
add_column :theme_settings, :created_at, :datetime, if_not_exists: true
|
|
50
|
+
add_column :theme_settings, :updated_at, :datetime, if_not_exists: true
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# The migration records nothing about whether it created the table or found
|
|
54
|
+
# it, so a down cannot tell the engine's table from the host's own theme. It
|
|
55
|
+
# refuses instead.
|
|
56
|
+
def down
|
|
57
|
+
return unless table_exists?(:theme_settings)
|
|
58
|
+
|
|
59
|
+
raise ActiveRecord::IrreversibleMigration,
|
|
60
|
+
"EnsureThemeSettingsTable cannot tell whether it created theme_settings or found the host's own; " \
|
|
61
|
+
"drop the table or the slug column by hand if this app truly owns neither."
|
|
62
|
+
end
|
|
63
|
+
end
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# The engine owns the shape of `image_caches`: ImageCache, Studio::ImageCache
|
|
2
|
+
# and Studio::EmailCatalog write the columns below on every host.
|
|
3
|
+
#
|
|
4
|
+
# Hosts that cache images already have the table (from their own migration);
|
|
5
|
+
# hosts that never did (cyvasse and moms-app when this shipped) get it here, so
|
|
6
|
+
# the email banner and logo uploads work on every app.
|
|
7
|
+
#
|
|
8
|
+
# A baseline, not a rebuild:
|
|
9
|
+
#
|
|
10
|
+
# - no table: create it in the engine's shape, with the owner nullable (an
|
|
11
|
+
# app-global image has no owner) and the indexes that back ImageCache's
|
|
12
|
+
# uniqueness validations;
|
|
13
|
+
# - a table: add any engine column it lacks, as a plain nullable column, and
|
|
14
|
+
# touch nothing else. No column is changed or dropped, no constraint is
|
|
15
|
+
# tightened and no index is added.
|
|
16
|
+
#
|
|
17
|
+
# Studio::HostSchema checks the same columns at boot.
|
|
18
|
+
class EnsureImageCachesTable < ActiveRecord::Migration[7.2]
|
|
19
|
+
def up
|
|
20
|
+
unless table_exists?(:image_caches)
|
|
21
|
+
create_table :image_caches do |t|
|
|
22
|
+
t.string :owner_type
|
|
23
|
+
t.bigint :owner_id
|
|
24
|
+
t.string :purpose, null: false
|
|
25
|
+
t.string :variant, null: false
|
|
26
|
+
t.string :s3_key, null: false
|
|
27
|
+
t.string :source_url
|
|
28
|
+
t.string :content_type
|
|
29
|
+
t.integer :bytes
|
|
30
|
+
|
|
31
|
+
t.timestamps
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
add_index :image_caches, %i[owner_type owner_id], name: "index_image_caches_on_owner"
|
|
35
|
+
add_index :image_caches, :s3_key, unique: true
|
|
36
|
+
add_index :image_caches, %i[owner_type owner_id purpose variant], unique: true,
|
|
37
|
+
name: "idx_image_caches_owner_purpose_variant"
|
|
38
|
+
return
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
add_column :image_caches, :owner_type, :string, if_not_exists: true
|
|
42
|
+
add_column :image_caches, :owner_id, :bigint, if_not_exists: true
|
|
43
|
+
add_column :image_caches, :purpose, :string, if_not_exists: true
|
|
44
|
+
add_column :image_caches, :variant, :string, if_not_exists: true
|
|
45
|
+
add_column :image_caches, :s3_key, :string, if_not_exists: true
|
|
46
|
+
add_column :image_caches, :source_url, :string, if_not_exists: true
|
|
47
|
+
add_column :image_caches, :content_type, :string, if_not_exists: true
|
|
48
|
+
add_column :image_caches, :bytes, :integer, if_not_exists: true
|
|
49
|
+
add_column :image_caches, :created_at, :datetime, if_not_exists: true
|
|
50
|
+
add_column :image_caches, :updated_at, :datetime, if_not_exists: true
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# The migration records nothing about whether it created the table or found
|
|
54
|
+
# it, so a down cannot tell the engine's table from the host's own cache. It
|
|
55
|
+
# refuses instead.
|
|
56
|
+
def down
|
|
57
|
+
return unless table_exists?(:image_caches)
|
|
58
|
+
|
|
59
|
+
raise ActiveRecord::IrreversibleMigration,
|
|
60
|
+
"EnsureImageCachesTable cannot tell whether it created image_caches or found the host's own; " \
|
|
61
|
+
"drop the table by hand if this app truly owns none of its rows."
|
|
62
|
+
end
|
|
63
|
+
end
|
data/lib/studio/engine.rb
CHANGED
|
@@ -298,6 +298,13 @@ module Studio
|
|
|
298
298
|
::User.ancestors.include?(::ActiveRecord::Base)
|
|
299
299
|
Studio.validate_user_contract!(::User)
|
|
300
300
|
end
|
|
301
|
+
|
|
302
|
+
# The host's error_logs, theme_settings and image_caches carry every
|
|
303
|
+
# column the engine's models write (Studio::HostSchema). Skipped in a
|
|
304
|
+
# rake task, which boots to migrate rather than to serve.
|
|
305
|
+
if Studio.active_record? && !Studio::HostSchema.inside_rake_task?
|
|
306
|
+
Studio::HostSchema.check!
|
|
307
|
+
end
|
|
301
308
|
end
|
|
302
309
|
|
|
303
310
|
end
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Studio
|
|
4
|
+
# The columns the engine's models write on tables the HOST holds: error_logs,
|
|
5
|
+
# theme_settings and image_caches. The engine's Ensure*Table migrations create
|
|
6
|
+
# or complete those tables; this checks, at boot, that the host has actually
|
|
7
|
+
# run them, so a missing column is named at startup instead of surfacing later
|
|
8
|
+
# as a 500 on the first save that writes it (a theme save on a host without
|
|
9
|
+
# theme_settings.slug was the case that prompted it).
|
|
10
|
+
#
|
|
11
|
+
# The check is one-directional: it looks only for REQUIRED columns that are
|
|
12
|
+
# absent. Extra columns, extra indexes, a different NOT NULL or a different
|
|
13
|
+
# type are the host's business and never reported.
|
|
14
|
+
#
|
|
15
|
+
# HOW LOUD, per environment (Studio.host_schema_check):
|
|
16
|
+
#
|
|
17
|
+
# :raise development and test, by default. A developer or a CI suite sees
|
|
18
|
+
# Studio::HostSchemaError at boot with the table, the column and the
|
|
19
|
+
# two commands that fix it.
|
|
20
|
+
# :log every other environment (production, and QA, which runs as
|
|
21
|
+
# production), by default. Rails.logger.error plus a Sentry message
|
|
22
|
+
# when the host loads sentry-ruby. It never raises there, for two
|
|
23
|
+
# reasons. Heroku's release phase boots the app to run db:migrate,
|
|
24
|
+
# the very command that adds the column, so a raise at boot would
|
|
25
|
+
# make the fix undeployable. And a missing column breaks the one
|
|
26
|
+
# surface that writes it (an admin theme save, an email banner
|
|
27
|
+
# upload); taking every page down to report it trades a small
|
|
28
|
+
# outage for a total one.
|
|
29
|
+
# false off.
|
|
30
|
+
#
|
|
31
|
+
# The check never runs inside a rake task (db:migrate, install:migrations,
|
|
32
|
+
# assets:precompile): those boot the app precisely to change or ignore the
|
|
33
|
+
# schema, and a report there would be wrong by the time the task finishes. It
|
|
34
|
+
# also stays quiet when the database cannot be reached; it has nothing to say
|
|
35
|
+
# about a schema it cannot read.
|
|
36
|
+
module HostSchema
|
|
37
|
+
REQUIRED_COLUMNS = {
|
|
38
|
+
"error_logs" => %w[
|
|
39
|
+
slug message inspect backtrace
|
|
40
|
+
target_type target_id target_name
|
|
41
|
+
parent_type parent_id parent_name
|
|
42
|
+
created_at updated_at
|
|
43
|
+
].freeze,
|
|
44
|
+
"theme_settings" => %w[
|
|
45
|
+
app_name slug primary dark light accent1 accent2 warning danger
|
|
46
|
+
created_at updated_at
|
|
47
|
+
].freeze,
|
|
48
|
+
"image_caches" => %w[
|
|
49
|
+
owner_type owner_id purpose variant s3_key source_url content_type bytes
|
|
50
|
+
created_at updated_at
|
|
51
|
+
].freeze
|
|
52
|
+
}.freeze
|
|
53
|
+
|
|
54
|
+
MODES = [:raise, :log, false].freeze
|
|
55
|
+
|
|
56
|
+
module_function
|
|
57
|
+
|
|
58
|
+
# { "table" => ["missing", "columns"] } for every required table that is
|
|
59
|
+
# absent (all its columns listed) or short of a column. Empty when the host
|
|
60
|
+
# satisfies the contract.
|
|
61
|
+
def missing_columns(connection)
|
|
62
|
+
REQUIRED_COLUMNS.each_with_object({}) do |(table, required), missing|
|
|
63
|
+
present = connection.table_exists?(table) ? connection.columns(table).map(&:name) : []
|
|
64
|
+
absent = required - present
|
|
65
|
+
missing[table] = absent if absent.any?
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def message(missing)
|
|
70
|
+
lines = missing.map do |table, columns|
|
|
71
|
+
if columns == REQUIRED_COLUMNS[table]
|
|
72
|
+
" #{table}: the table is missing"
|
|
73
|
+
else
|
|
74
|
+
" #{table}: missing #{columns.join(', ')}"
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
<<~MSG
|
|
79
|
+
studio-engine: this app's database is missing columns the engine's models write.
|
|
80
|
+
|
|
81
|
+
#{lines.join("\n")}
|
|
82
|
+
|
|
83
|
+
Install and run the engine's migrations (they create a missing table, add
|
|
84
|
+
a missing column and change nothing else):
|
|
85
|
+
|
|
86
|
+
bin/rails studio_engine:install:migrations
|
|
87
|
+
bin/rails db:migrate
|
|
88
|
+
|
|
89
|
+
Set Studio.host_schema_check = false in config/initializers/studio.rb to
|
|
90
|
+
silence this check.
|
|
91
|
+
MSG
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
# The mode in force: the host's Studio.host_schema_check, or :raise in
|
|
95
|
+
# development and test and :log everywhere else.
|
|
96
|
+
def mode(setting: Studio.host_schema_check, env: Rails.env)
|
|
97
|
+
return setting unless setting.nil?
|
|
98
|
+
|
|
99
|
+
env.development? || env.test? ? :raise : :log
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
# The boot hook. Returns the missing-columns hash it found (empty when the
|
|
103
|
+
# host is whole or the check was skipped) and acts on it per `mode`.
|
|
104
|
+
def check!(connection: nil, mode: self.mode, logger: Rails.logger)
|
|
105
|
+
return {} if mode == false
|
|
106
|
+
|
|
107
|
+
missing =
|
|
108
|
+
begin
|
|
109
|
+
if connection
|
|
110
|
+
missing_columns(connection)
|
|
111
|
+
else
|
|
112
|
+
ActiveRecord::Base.connection_pool.with_connection { |conn| missing_columns(conn) }
|
|
113
|
+
end
|
|
114
|
+
rescue ActiveRecord::ActiveRecordError => e
|
|
115
|
+
logger&.debug("[studio-engine] host schema check skipped: #{e.class}: #{e.message}")
|
|
116
|
+
return {}
|
|
117
|
+
end
|
|
118
|
+
return missing if missing.empty?
|
|
119
|
+
|
|
120
|
+
text = message(missing)
|
|
121
|
+
raise Studio::HostSchemaError, text if mode == :raise
|
|
122
|
+
|
|
123
|
+
logger&.error("[studio-engine] #{text}")
|
|
124
|
+
report_to_sentry(text)
|
|
125
|
+
missing
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
# True while a rake task is running: the app booted to migrate, install or
|
|
129
|
+
# precompile, not to serve.
|
|
130
|
+
def inside_rake_task?
|
|
131
|
+
defined?(::Rake) && ::Rake.respond_to?(:application) &&
|
|
132
|
+
::Rake.application.respond_to?(:top_level_tasks) &&
|
|
133
|
+
::Rake.application.top_level_tasks.any?
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def report_to_sentry(text)
|
|
137
|
+
return unless defined?(::Sentry) && ::Sentry.respond_to?(:capture_message)
|
|
138
|
+
|
|
139
|
+
::Sentry.capture_message(text, level: :error)
|
|
140
|
+
rescue StandardError
|
|
141
|
+
nil
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
end
|
data/lib/studio/version.rb
CHANGED
data/lib/studio.rb
CHANGED
|
@@ -42,6 +42,7 @@ require "studio/public_user"
|
|
|
42
42
|
require "studio/name_parts"
|
|
43
43
|
require "studio/s3"
|
|
44
44
|
require "studio/image_cache"
|
|
45
|
+
require "studio/host_schema"
|
|
45
46
|
require "studio/link_token"
|
|
46
47
|
require "studio/link_resolution"
|
|
47
48
|
require "studio/session_fingerprint"
|
|
@@ -1060,6 +1061,11 @@ module Studio
|
|
|
1060
1061
|
# that intentionally break the contract).
|
|
1061
1062
|
mattr_accessor :validate_user_contract, default: true
|
|
1062
1063
|
|
|
1064
|
+
# How loudly the boot check reports a host database missing a column the
|
|
1065
|
+
# engine's models write (Studio::HostSchema): :raise, :log, or false for off.
|
|
1066
|
+
# nil, the default, means :raise in development and test and :log elsewhere.
|
|
1067
|
+
mattr_accessor :host_schema_check, default: nil
|
|
1068
|
+
|
|
1063
1069
|
# Does the host load ActiveRecord at all? True for every app that requires
|
|
1064
1070
|
# `rails/all` or `active_record/railtie` (all the engine's database-backed
|
|
1065
1071
|
# consumers); false for a FOOTER-ONLY consumer, an app with no database that
|
|
@@ -1091,6 +1097,7 @@ module Studio
|
|
|
1091
1097
|
PASSWORD_USER_INSTANCE_METHODS = %i[authenticate].freeze
|
|
1092
1098
|
|
|
1093
1099
|
class UserContractError < StandardError; end
|
|
1100
|
+
class HostSchemaError < StandardError; end
|
|
1094
1101
|
|
|
1095
1102
|
def self.configure
|
|
1096
1103
|
yield self
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: studio-engine
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.92.
|
|
4
|
+
version: 0.92.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Alex McRitchie
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-10-
|
|
11
|
+
date: 2026-10-07 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rails
|
|
@@ -640,6 +640,9 @@ files:
|
|
|
640
640
|
- db/migrate/20260902000002_add_expectation_to_studio_knowledge_docs.rb
|
|
641
641
|
- db/migrate/20260930120000_create_studio_site_identities.rb
|
|
642
642
|
- db/migrate/20261005120000_create_studio_survey_responses.rb
|
|
643
|
+
- db/migrate/20261006120001_ensure_error_logs_table.rb
|
|
644
|
+
- db/migrate/20261006120002_ensure_theme_settings_table.rb
|
|
645
|
+
- db/migrate/20261006120003_ensure_image_caches_table.rb
|
|
643
646
|
- docs/BOOKING.md
|
|
644
647
|
- docs/SITE_FOOTER.md
|
|
645
648
|
- lib/active_storage/service/studio_trash_s3_service.rb
|
|
@@ -658,6 +661,7 @@ files:
|
|
|
658
661
|
- lib/studio/geo.rb
|
|
659
662
|
- lib/studio/geo/countries.rb
|
|
660
663
|
- lib/studio/geo/lookup.rb
|
|
664
|
+
- lib/studio/host_schema.rb
|
|
661
665
|
- lib/studio/image_cache.rb
|
|
662
666
|
- lib/studio/ip_locations.rb
|
|
663
667
|
- lib/studio/js_identifier.rb
|