summaryrefslogtreecommitdiff
path: root/INSTALL.md
diff options
context:
space:
mode:
authorerdgeist <erdgeist@erdgeist.org>2026-08-09 23:37:59 +0200
committererdgeist <erdgeist@erdgeist.org>2026-08-09 23:37:59 +0200
commitbb356127ddc7f9ea735e287180057400f1631889 (patch)
tree9589f21d7007303d050899e58cecff4f1d7d289e /INSTALL.md
parent5690cf4d4e05eafdfd2e270bbdf1a925114d0f76 (diff)
Document loading the schema as the install path
db/schema.rb is in the repository, so a fresh install loads it rather than replaying migrations. db:setup and db:reset are safe; db:migrate is for an existing installation. The search_vector trigger is reinstalled by a db:schema:load hook and at boot, so a fresh install needs nothing further. A restore from a dump that predates the trigger needs pages:backfill_search_vector, now listed under one-shot tasks. The test database is no longer created by hand: Rails' db:test:prepare drops and recreates it from database.yml.
Diffstat (limited to 'INSTALL.md')
-rw-r--r--INSTALL.md30
1 files changed, 19 insertions, 11 deletions
diff --git a/INSTALL.md b/INSTALL.md
index 55bf768c..bad2c271 100644
--- a/INSTALL.md
+++ b/INSTALL.md
@@ -109,8 +109,6 @@ ALTER ROLE rails CREATEDB;
109 109
110CREATE DATABASE cccms_dev OWNER rails ENCODING 'UTF8' 110CREATE DATABASE cccms_dev OWNER rails ENCODING 'UTF8'
111 LC_COLLATE 'en_US.UTF-8' LC_CTYPE 'en_US.UTF-8' TEMPLATE template0; 111 LC_COLLATE 'en_US.UTF-8' LC_CTYPE 'en_US.UTF-8' TEMPLATE template0;
112CREATE DATABASE psql_test OWNER rails ENCODING 'UTF8'
113 LC_COLLATE 'en_US.UTF-8' LC_CTYPE 'en_US.UTF-8' TEMPLATE template0;
114``` 112```
115 113
116`CREATEDB` is needed because the test suite creates and drops its own 114`CREATEDB` is needed because the test suite creates and drops its own
@@ -153,18 +151,25 @@ production:
153Cccms::Application.config.secret_key_base = "<64 hex chars, e.g. from `rails secret`>" 151Cccms::Application.config.secret_key_base = "<64 hex chars, e.g. from `rails secret`>"
154``` 152```
155 153
156### 4a. Migrate. Never load the schema. 154### 4a. Load the schema
155
156 bundle exec rails db:schema:load
157 157
158 bundle exec rails db:migrate 158`db/schema.rb` is in the repository and is the authoritative description
159of the database. Replaying the migration chain is not a supported route:
160the oldest migrations predate Rails 4, and some columns were only ever
161applied by hand. `db:setup` and `db:reset` are safe.
159 162
160Do not run `db:setup` or `db:schema:load`. 163`bundle exec rails db:migrate` is for an existing installation โ€” see the
164deploy sequence in ยง7.
161 165
162`db/schema.rb` is gitignored, and it could not be used even if it were 166The full-text `search_vector` column is maintained by a PostgreSQL trigger,
163present: the full-text `search_vector` column is maintained by a PostgreSQL 167which Ruby's schema format cannot express. `db:schema:load` reinstalls it
164trigger, and Ruby's schema format cannot express triggers. A schema-loaded 168through a rake hook, and the application reinstalls it at boot, so a fresh
165database gets the column and its GIN index with nothing populating them, 169install needs nothing further. A database restored from a dump taken before
166and site search then silently returns no results. Migrations are the only 170the trigger existed has rows it cannot repair, because the trigger fires
167complete record of the structure. 171only on insert or update. You have to run `pages:backfill_search_vector`
172once after such a restore.
168 173
169## 5. First start 174## 5. First start
170 175
@@ -296,6 +301,9 @@ old Ruby.
296 second factor from the shell when every administrator is locked out. 301 second factor from the shell when every administrator is locked out.
297 Deliberately unwitnessed โ€” there is no actor to attribute a shell 302 Deliberately unwitnessed โ€” there is no actor to attribute a shell
298 command to. 303 command to.
304- `pages:backfill_search_vector` fills `search_vector` for rows that have
305 none, and installs the trigger first. Needed after restoring a dump that
306 predates the trigger; harmless otherwise, since it only fills nulls.
299 307
300Logs are in `log/`, gitignored. The action log inside the application at 308Logs are in `log/`, gitignored. The action log inside the application at
301`/admin/log` records who changed what; `log/production.log` records 309`/admin/log` records who changed what; `log/production.log` records