From 87ff920627e143f69f5b8622f7076493c50058b2 Mon Sep 17 00:00:00 2001 From: Tataihono Nikora Date: Sat, 28 Mar 2026 09:04:45 +0000 Subject: [PATCH 1/6] docs: Add requirements and plan for simplify-to-sermons refactor --- ...-03-28-simplify-to-sermons-requirements.md | 54 ++++ ...8-001-refactor-simplify-to-sermons-plan.md | 302 ++++++++++++++++++ 2 files changed, 356 insertions(+) create mode 100644 docs/brainstorms/2026-03-28-simplify-to-sermons-requirements.md create mode 100644 docs/plans/2026-03-28-001-refactor-simplify-to-sermons-plan.md diff --git a/docs/brainstorms/2026-03-28-simplify-to-sermons-requirements.md b/docs/brainstorms/2026-03-28-simplify-to-sermons-requirements.md new file mode 100644 index 0000000..cfa046f --- /dev/null +++ b/docs/brainstorms/2026-03-28-simplify-to-sermons-requirements.md @@ -0,0 +1,54 @@ +--- +date: 2026-03-28 +topic: simplify-to-sermons +--- + +# Simplify App to Sermons-Only + +## Problem Frame + +The app (resources.ev.church) was built to support multiple resource types (sermons, articles) and location-based content (events, prayers, services, steps). In practice, only sermons exist (652 records). The unused models, admin panels, API types, and STI hierarchy add complexity without value. Simplifying to a sermons-focused app reduces cognitive load, code surface, and maintenance burden. + +## Requirements + +- R1. Rename `resources` table to `sermons` and `Resource` model to `Sermon` (drop STI, remove `type` column) +- R2. Rename all join tables: `resource_connection_authors` → `sermon_authors`, `resource_connection_scriptures` → `sermon_scriptures`, `resource_connection_series` → `sermon_series`, `resource_connection_topics` → `sermon_topics` +- R3. Drop tables: `steps`, `locations`, `location_events`, `location_prayers`, `location_services`, `location_connection_steps` +- R4. Remove all models, admin resources, controllers, views, decorators, and GraphQL types for dropped entities (Location, Location::Event, Location::Prayer, Location::Service, Step, Resource::Article) +- R5. Update public views: rename resource references to sermon (routes, controllers, view templates, partials) +- R6. Update ActiveAdmin: replace Resource admin with Sermon admin, remove dropped model admin pages +- R7. Update GraphQL API: rename Resource type/queries to Sermon, remove dropped types/queries (locations, events, prayers, services, steps) +- R8. Preserve all existing sermon data and relationships (authors, categories, topics, scriptures, series, attachments) +- R9. Keep users, roles, categories, topics, scriptures, series, and authors unchanged + +## Success Criteria + +- All 652 sermons accessible with their relationships intact +- No references to Resource, Location, Step, Prayer, Service, Event, or Article in application code +- Admin, public views, and GraphQL API all use "Sermon" terminology +- All migrations are reversible + +## Scope Boundaries + +- 3 locations and 17 events are intentionally dropped (no data preservation needed) +- User/auth system unchanged +- No URL redirect mapping from old routes (clean break) +- Categories, topics, scriptures, series, authors models unchanged (only their relationship to Resource→Sermon changes) + +## Key Decisions + +- **Flat Sermon model (no STI)**: Since only sermons exist, drop the Resource parent class and type column entirely. Simpler model, simpler queries. +- **Rename tables via migration**: Rename rather than drop+recreate to preserve data and UUIDs. +- **Drop all location-related models**: Zero public usage, minimal data (all droppable). + +## Outstanding Questions + +### Deferred to Planning + +- [Affects R1][Technical] Should `friendly_id` slugs be regenerated for sermons, or keep existing slug behavior? +- [Affects R5][Technical] Should public URLs change from `/resources` to `/sermons`, or keep `/resources` for SEO continuity? +- [Affects R2][Technical] Determine exact migration strategy for renaming tables while preserving foreign keys and indexes + +## Next Steps + +→ `/ce:plan` for structured implementation planning diff --git a/docs/plans/2026-03-28-001-refactor-simplify-to-sermons-plan.md b/docs/plans/2026-03-28-001-refactor-simplify-to-sermons-plan.md new file mode 100644 index 0000000..f0da7fc --- /dev/null +++ b/docs/plans/2026-03-28-001-refactor-simplify-to-sermons-plan.md @@ -0,0 +1,302 @@ +--- +title: "refactor: Simplify app from Resources to Sermons" +type: refactor +status: active +date: 2026-03-28 +origin: docs/brainstorms/2026-03-28-simplify-to-sermons-requirements.md +--- + +# Simplify App from Resources to Sermons + +## Overview + +Drop unused models (Location, Step, Event, Prayer, Service, Article), rename Resource to Sermon (removing STI), rename all join tables, and update all three surfaces (ActiveAdmin, public views, GraphQL API). 100 files affected: 62 to modify, 38 to delete. All 652 sermons and their relationships are preserved. + +## Problem Frame + +The app was built for multiple resource types and location-based content, but only sermons exist. The unused STI hierarchy, empty models, and dead admin/API surfaces add complexity without value. (see origin: docs/brainstorms/2026-03-28-simplify-to-sermons-requirements.md) + +## Requirements Trace + +- R1. Rename `resources` table to `sermons`, `Resource` model to `Sermon` (drop STI, remove `type` column) +- R2. Rename join tables: `resource_connection_*` → `sermon_*` +- R3. Drop tables: `steps`, `locations`, `location_events`, `location_prayers`, `location_services`, `location_connection_steps` +- R4. Remove all code for dropped entities +- R5. Update public views (keep `/resources` URL paths for link continuity) +- R6. Update ActiveAdmin: Sermon admin replaces Resource admin +- R7. Update GraphQL API: Sermon type/queries replace Resource +- R8. Preserve all sermon data and relationships +- R9. Keep users, roles, categories, topics, scriptures, series, authors unchanged + +## Scope Boundaries + +- 3 locations and 17 events are intentionally dropped +- Public URLs stay at `/resources` (not renamed to `/sermons`) for link continuity +- User/auth system unchanged +- No redirect mapping from old routes +- Categories, topics, scriptures, series, authors models unchanged — only their associations update + +## Context & Research + +### Relevant Code and Patterns + +- `Resource` model (`app/models/resource.rb`) — STI base class with all logic; subtypes `Resource::Sermon` and `Resource::Article` are empty +- `Resource::Connection` module — uses `self.table_name_prefix = 'resource_connection_'` to map namespace to table names +- `ResourceTypeConstraint` (`app/constraints/resource_type_constraint.rb`) — validates `resource_type` param against `Resource::TYPES`; can be deleted entirely +- `ResourceDecorator` — `type_title` and `type_param` methods used extensively in views; simplify to static "Sermon" or remove +- Controllers (`resources_controller.rb`, `resources/authors_controller.rb`, etc.) — all query `Resource` with `Resource::TYPES` filtering +- Cache key in `resources_controller.rb` uses `params[:resource_type]` — needs simplification, not just renaming +- GraphQL mutations directory is empty (only `.keep`) — cleanup limited to query types and object definitions +- `active_storage_attachments.record_type` stores `'Resource'` — needs data migration to `'Sermon'` +- `friendly_id_slugs.sluggable_type` — needs data migration if slugs exist +- `active_admin_comments.resource_type` — ActiveAdmin's own polymorphic column, stores `'Resource::Sermon'`; needs update +- `roles` table has `resource_type`/`resource_id` — these are Rolify's own polymorphic columns, unrelated to our Resource model + +### Institutional Learnings + +- ActiveAdmin assets use Sprockets (not Shakapacker) — don't touch `active_admin.scss` when removing admin registrations +- GraphQL mutations are empty scaffolding — simplifies API cleanup + +## Key Technical Decisions + +- **Keep `/resources` URL paths**: Public URLs stay as `/resources` for link/SEO continuity. The controller and route names stay as `resources`, but internally they query `Sermon`. This means the controller is named `ResourcesController` but queries the `Sermon` model. +- **Use `rename_table` migrations**: PostgreSQL `rename_table` preserves indexes automatically. Foreign key constraints need manual verification/update in the migration. +- **Data migration for polymorphic types**: `active_storage_attachments.record_type`, `friendly_id_slugs.sluggable_type`, and `active_admin_comments.resource_type` all store class names as strings. These must be updated from `'Resource'`/`'Resource::Sermon'` to `'Sermon'` in the same migration. +- **Delete `ResourceTypeConstraint`**: No longer needed — only one type exists. Routes simplify. +- **Flatten `Sermon::Connection` namespace**: Rename join models from `Resource::Connection::Author` to `SermonAuthor` (flat, no namespace). Simpler than maintaining a connection module. Table names: `sermon_authors`, `sermon_scriptures`, `sermon_series`, `sermon_topics`. + +## Open Questions + +### Resolved During Planning + +- **friendly_id slugs**: The `friendly_id_slugs` table is empty (0 rows), so no data migration needed for slugs. The `friendly_id` config on the model just needs to reference `Sermon` instead of `Resource`. +- **Migration strategy for foreign keys**: PostgreSQL `rename_table` handles indexes. Foreign keys referencing renamed tables need explicit `rename` in the migration since Rails `rename_table` doesn't auto-update FK references on other tables. +- **Public URL paths**: Keep `/resources` for link continuity (user decision). + +### Deferred to Implementation + +- **Exact cache key format after simplification**: The current cache key uses `resource_type` param. Determine final cache key during implementation after seeing how the controller simplifies. + +## Implementation Units + +- [ ] **Unit 1: Database migration — rename tables and update polymorphic types** + + **Goal:** Rename `resources` → `sermons`, rename all 4 join tables, drop 6 unused tables, remove `type` column, update polymorphic string references. (R1, R2, R3, R8) + + **Dependencies:** None — first step + + **Files:** + - Create: `db/migrate/YYYYMMDD_simplify_resources_to_sermons.rb` + - Auto-updated: `db/schema.rb` + + **Approach:** + - Single migration with `rename_table` for each table rename + - `remove_column :resources, :type` (after rename to `sermons`) + - `drop_table` for: `steps`, `locations`, `location_events`, `location_prayers`, `location_services`, `location_connection_steps` + - Update polymorphic string columns: + - `active_storage_attachments` where `record_type = 'Resource'` → `'Sermon'` + - `active_storage_blobs` — no change needed (no polymorphic type column) + - `active_admin_comments` where `resource_type` contains `'Resource'` → update to `'Sermon'` + - Update foreign key constraints that reference renamed tables + - Migration must be reversible + + **Test scenarios:** + - `sermons` table exists with all 652 rows, no `type` column + - All 4 join tables renamed correctly with data intact + - All 6 dropped tables no longer exist + - `active_storage_attachments.record_type` all say `'Sermon'` + - Foreign key constraints reference correct table names + + **Verification:** + - `rails db:migrate` succeeds + - `rails db:rollback` succeeds (reversibility) + - Row counts match pre-migration counts + +- [ ] **Unit 2: Models — rename Resource to Sermon, drop unused models** + + **Goal:** Create `Sermon` model, flatten join models, delete all location/step/article model files. (R1, R2, R4, R9) + + **Dependencies:** Unit 1 + + **Files:** + - Create: `app/models/sermon.rb` (from `app/models/resource.rb` content, drop STI) + - Create: `app/models/sermon_author.rb` (flat, replaces `Resource::Connection::Author`) + - Create: `app/models/sermon_scripture.rb` + - Create: `app/models/sermon_series.rb` + - Create: `app/models/sermon_topic.rb` + - Modify: `app/models/author.rb`, `app/models/scripture.rb`, `app/models/series.rb`, `app/models/category/topic.rb` (update associations) + - Delete: `app/models/resource.rb`, `app/models/resource/` directory (sermon.rb, article.rb, connection.rb, connection/*.rb) + - Delete: `app/models/step.rb`, `app/models/location.rb`, `app/models/location/` directory + - Test: `spec/models/sermon_spec.rb` + + **Approach:** + - `Sermon` model: copy `Resource` logic, remove `self.inheritance_column`, remove `TYPES` constant, set `self.table_name = 'sermons'` + - Flatten join models: `SermonAuthor` with `self.table_name = 'sermon_authors'`, simple `belongs_to :sermon` + `belongs_to :author` + - Update association models: `Author`, `Scripture`, `Series`, `Category::Topic` — change `class_name: 'Resource::Connection::Author'` to `class_name: 'SermonAuthor'`, change `has_many :resources` to `has_many :sermons` + + **Patterns to follow:** + - Existing `Resource` model for the Sermon model structure + - Existing `Resource::Connection::Author` for join model pattern (simplify to flat) + + **Verification:** + - `Sermon.count` returns 652 + - `Sermon.first.authors` returns associated authors + - No `Resource` or `Location` or `Step` constants defined + +- [ ] **Unit 3: Decorators and constraints — rename and clean up** + + **Goal:** Rename ResourceDecorator to SermonDecorator, delete article decorator, delete ResourceTypeConstraint. (R4, R5) + + **Dependencies:** Unit 2 + + **Files:** + - Create: `app/decorators/sermon_decorator.rb` (from resource_decorator.rb, simplify type methods) + - Create: `app/decorators/sermon_scripture_decorator.rb` (from resource/connection/scripture_decorator.rb) + - Delete: `app/decorators/resource_decorator.rb`, `app/decorators/resource/` directory + - Delete: `app/constraints/resource_type_constraint.rb` + + **Approach:** + - `SermonDecorator`: remove `type_title`/`type_param` methods or make them return static "Sermon"/"sermon" + - Delete `ResourceTypeConstraint` — no longer needed with single type + + **Verification:** + - `SermonDecorator` works for all existing decorator method calls in views + - No references to `ResourceDecorator` or `ResourceTypeConstraint` remain + +- [ ] **Unit 4: Controllers and routes — update to use Sermon model** + + **Goal:** Update controllers to query `Sermon` instead of `Resource`. Simplify routes (remove type constraint). Keep `/resources` URL paths. (R5) + + **Dependencies:** Unit 2, Unit 3 + + **Files:** + - Modify: `app/controllers/resources_controller.rb` (query `Sermon` instead of `Resource`, simplify cache key) + - Modify: `app/controllers/resources/authors_controller.rb` (query `Sermon`) + - Modify: `app/controllers/resources/scriptures_controller.rb` + - Modify: `app/controllers/resources/series_controller.rb` + - Modify: `app/controllers/resources/topics_controller.rb` + - Modify: `config/routes.rb` (remove `ResourceTypeConstraint`, simplify resource routes) + - Test: `spec/requests/resources_spec.rb` + + **Approach:** + - Controllers stay named `ResourcesController` etc. (URL paths unchanged) + - Replace `::Resource` queries with `::Sermon` + - Remove `Resource::TYPES` references and type filtering logic + - Simplify cache keys (remove `resource_type` param dependency) + - Routes: remove `constraints: ResourceTypeConstraint.new` and `(:resource_type)` segments + + **Verification:** + - `/resources` loads and shows sermons + - `/resources/:id` shows a sermon + - `/resources/authors`, `/resources/scriptures`, `/resources/series`, `/resources/topics` all work + - RSS feed at `/resources.rss` works + +- [ ] **Unit 5: Views — update templates to use Sermon** + + **Goal:** Update all view templates and partials to reference Sermon instead of Resource. Remove article/type-switching references. (R5) + + **Dependencies:** Unit 3, Unit 4 + + **Files:** + - Modify: All 22 view files in `app/views/resources/`, `app/views/shared/resource/`, `app/views/shared/`, `app/views/application/`, `app/views/pages/` + - Key changes in: `home.html.erb`, `_listing_header.html.erb`, `_links.html.erb`, `_menu.html.erb` + + **Approach:** + - Replace `Resource.published` with `Sermon.published` + - Remove type-switching logic (`Resource.articles`, `Resource.sermons` → just `Sermon`) + - Remove `resource_type` param references from navigation + - Keep local variable names as `resource`/`resources` in partials if cleaner (avoid renaming every local var) + - Simplify `_listing_header.html.erb` — remove article/sermon tabs since only sermons exist + + **Verification:** + - Homepage loads with featured sermons + - All browse-by pages (authors, scriptures, series, topics) render correctly + - No "Article" references visible in the UI + - Navigation links work + +- [ ] **Unit 6: ActiveAdmin — replace Resource admin with Sermon admin** + + **Goal:** Create Sermon admin, delete all dropped model admin files. (R6) + + **Dependencies:** Unit 2 + + **Files:** + - Create: `app/admin/sermons.rb` (from `resource_sermons.rb`, register `Sermon` instead of `Resource::Sermon`) + - Delete: `app/admin/resource_sermons.rb`, `app/admin/resource_articles.rb` + - Delete: `app/admin/locations.rb`, `app/admin/location_events.rb`, `app/admin/location_services.rb`, `app/admin/location_prayers.rb`, `app/admin/location_connection_steps.rb`, `app/admin/steps.rb` + + **Approach:** + - `ActiveAdmin.register Sermon` — copy permit_params and form/index/show configuration from `resource_sermons.rb` + - Remove `Resource::Sermon` specific references + - Don't touch `active_admin.scss` (Sprockets pipeline must stay intact) + + **Verification:** + - `/admin/sermons` loads with all 652 sermons + - Create/edit/delete sermon works + - No admin pages for locations, steps, events, prayers, services, articles + - ActiveAdmin CSS renders correctly (Sprockets intact) + +- [ ] **Unit 7: GraphQL API — rename to Sermon types** + + **Goal:** Rename Resource GraphQL type/query to Sermon, remove all dropped model types/queries. (R7) + + **Dependencies:** Unit 2 + + **Files:** + - Create: `app/graphql/types/sermon_type.rb` (from `resource_type.rb`) + - Create: `app/graphql/types/sermon_scripture_type.rb` (from `resource/connection/scripture_type.rb`) + - Create: `app/graphql/queries/sermons_query.rb` (from `resources_query.rb`) + - Modify: `app/graphql/types/query_type.rb` (rename `resources` field to `sermons`, remove `locations`, `events`, `prayers`, `steps` fields) + - Delete: `app/graphql/types/resource_type.rb`, `app/graphql/types/resource/` directory + - Delete: All location/step GraphQL types and queries (10 files) + + **Approach:** + - `Types::SermonType` — rename fields, remove `Resource::Connection::ScriptureType` reference + - `Queries::SermonsQuery` — query `::Sermon` instead of `::Resource`, remove `Resource::TYPES` filtering + - Keep `ChurchResourcesSchema` class name (app name hasn't changed) + + **Verification:** + - `{ sermons { nodes { id name } } }` query works + - Introspection shows `Sermon` type, no `Resource`/`Location`/`Step` types + - GraphiQL docs explorer shows updated schema + +- [ ] **Unit 8: Tests — update specs and factories** + + **Goal:** Rename specs/factories for Sermon, delete specs for dropped models. (R8) + + **Dependencies:** Units 2-7 + + **Files:** + - Create: `spec/models/sermon_spec.rb`, `spec/factories/sermons.rb` + - Create: `spec/models/sermon_author_spec.rb` (etc. for join models) + - Create: `spec/factories/sermon_authors.rb` (etc.) + - Modify: `spec/requests/resources_spec.rb` (update to use Sermon factory) + - Modify: `spec/features/active_admin_smoke_spec.rb` (update paths, remove dropped model tests) + - Delete: 12 spec/factory files for dropped models + + **Verification:** + - Full test suite passes + - No references to `Resource`, `Location`, `Step` in test files + +## System-Wide Impact + +- **Polymorphic type columns**: `active_storage_attachments.record_type` and `active_admin_comments.resource_type` store class name strings. Migration must update these atomically with the table rename. +- **Rolify `roles` table**: Has `resource_type`/`resource_id` columns but these are Rolify's own polymorphic system, unrelated to our Resource model. No change needed. +- **Cache invalidation**: Controller cache keys reference `resource_type` params. After simplification, cached pages with old keys will naturally expire. No explicit cache purge needed. +- **Active Storage**: Attachments link via `record_type: 'Resource'`. After data migration to `'Sermon'`, all existing file references continue working (S3 keys unchanged). +- **GraphQL API consumers**: The `resources` query field renames to `sermons`. This is a breaking API change. If external consumers exist, they need notification. + +## Risks & Dependencies + +| Risk | Severity | Mitigation | +|---|---|---| +| Migration fails on production data | High | Test migration against production data dump locally first. Ensure reversibility. | +| Polymorphic type mismatch after rename | High | Update ALL polymorphic `record_type`/`resource_type` columns in the same migration. | +| GraphQL breaking change for API consumers | Medium | Verify if any external apps consume the API before deploying. | +| ActiveAdmin asset breakage | Low | Don't touch `active_admin.scss`. Only modify Ruby registration files. | + +## Sources & References + +- **Origin document:** [docs/brainstorms/2026-03-28-simplify-to-sermons-requirements.md](docs/brainstorms/2026-03-28-simplify-to-sermons-requirements.md) +- Related code: `app/models/resource.rb`, `app/models/resource/`, `app/models/location/`, `app/admin/`, `app/graphql/`, `app/controllers/resources_controller.rb` +- Rails guide: `rename_table` preserves indexes in PostgreSQL From 6988fe71e4f75c4df326ef1f6b77fb32070fc4aa Mon Sep 17 00:00:00 2001 From: Tataihono Nikora Date: Sat, 28 Mar 2026 09:19:56 +0000 Subject: [PATCH 2/6] refactor: Simplify app from Resources to Sermons Drop unused models (Location, Step, Event, Prayer, Service, Article), rename Resource to Sermon removing STI, rename all join tables, and update all three surfaces (ActiveAdmin, public views, GraphQL API). 111 files changed, 556 insertions, 1342 deletions. All 652 sermons and their relationships preserved. Public URLs stay at /resources. Co-Authored-By: Claude Opus 4.6 (1M context) --- app/admin/location_connection_steps.rb | 26 --- app/admin/location_events.rb | 53 ----- app/admin/location_prayers.rb | 18 -- app/admin/location_services.rb | 17 -- app/admin/locations.rb | 22 -- app/admin/resource_articles.rb | 44 ---- app/admin/{resource_sermons.rb => sermons.rb} | 12 +- app/admin/steps.rb | 63 ------ app/constraints/resource_type_constraint.rb | 7 - .../resources/authors_controller.rb | 9 +- .../resources/scriptures_controller.rb | 9 +- .../resources/series_controller.rb | 9 +- .../resources/topics_controller.rb | 17 +- app/controllers/resources_controller.rb | 16 +- app/decorators/resource/article_decorator.rb | 7 - app/decorators/resource/sermon_decorator.rb | 15 -- app/decorators/resource_decorator.rb | 49 ----- app/decorators/sermon_decorator.rb | 61 ++++++ ...rator.rb => sermon_scripture_decorator.rb} | 2 +- app/graphql/queries/authors_query.rb | 13 +- app/graphql/queries/categories_query.rb | 13 +- app/graphql/queries/events_query.rb | 30 --- app/graphql/queries/locations_query.rb | 21 -- app/graphql/queries/prayers_query.rb | 27 --- app/graphql/queries/scriptures_query.rb | 13 +- app/graphql/queries/series_query.rb | 17 +- .../{resources_query.rb => sermons_query.rb} | 18 +- app/graphql/queries/steps_query.rb | 34 --- app/graphql/queries/topic_query.rb | 13 +- .../types/location/connection/step_type.rb | 14 -- app/graphql/types/location/event_type.rb | 25 --- app/graphql/types/location/prayer_type.rb | 20 -- app/graphql/types/location/service_type.rb | 9 - app/graphql/types/location_type.rb | 24 -- app/graphql/types/query_type.rb | 6 +- ...pture_type.rb => sermon_scripture_type.rb} | 6 +- .../{resource_type.rb => sermon_type.rb} | 4 +- app/graphql/types/step_type.rb | 17 -- app/models/author.rb | 6 +- app/models/category/topic.rb | 6 +- app/models/location.rb | 29 --- app/models/location/connection.rb | 7 - app/models/location/connection/step.rb | 15 -- app/models/location/event.rb | 29 --- app/models/location/prayer.rb | 25 --- app/models/location/service.rb | 14 -- app/models/resource.rb | 51 ----- app/models/resource/article.rb | 4 - app/models/resource/connection.rb | 7 - app/models/resource/connection/series.rb | 14 -- app/models/resource/sermon.rb | 4 - app/models/scripture.rb | 6 +- app/models/series.rb | 6 +- app/models/sermon.rb | 45 ++++ .../connection/author.rb => sermon_author.rb} | 8 +- .../scripture.rb => sermon_scripture.rb} | 8 +- app/models/sermon_series.rb | 14 ++ .../connection/topic.rb => sermon_topic.rb} | 8 +- app/models/step.rb | 28 --- app/services/import/wpfc_service.rb | 8 +- app/views/application/_links.html.erb | 11 +- app/views/application/_menu.html.erb | 22 +- app/views/pages/home.html.erb | 8 +- app/views/resources/authors/index.html.erb | 4 +- app/views/resources/authors/show.html.erb | 2 +- app/views/resources/index.html.erb | 2 +- app/views/resources/index.rss.builder | 4 +- app/views/resources/scriptures/index.html.erb | 4 +- app/views/resources/scriptures/show.html.erb | 2 +- app/views/resources/series/index.html.erb | 4 +- app/views/resources/series/show.html.erb | 2 +- app/views/resources/show.html.erb | 20 +- app/views/resources/topics/index.html.erb | 6 +- app/views/resources/topics/show.html.erb | 2 +- app/views/shared/_listing_header.html.erb | 34 +-- app/views/shared/resource/_card.html.erb | 6 +- app/views/shared/resource/_feature.html.erb | 8 +- app/views/shared/resource/_item.html.erb | 8 +- .../shared/resource/_scripture_list.html.erb | 8 +- config/routes.rb | 3 +- ...328000000_simplify_resources_to_sermons.rb | 207 ++++++++++++++++++ db/schema.rb | 170 ++++---------- spec/factories/location/connection/steps.rb | 12 - spec/factories/location/events.rb | 15 -- spec/factories/location/prayers.rb | 10 - spec/factories/location/services.rb | 9 - spec/factories/locations.rb | 10 - spec/factories/resource/connection/authors.rb | 8 - .../resource/connection/scriptures.rb | 8 - spec/factories/resource/connection/series.rb | 8 - spec/factories/resource/connection/topics.rb | 8 - spec/factories/sermon_authors.rb | 8 + spec/factories/sermon_scriptures.rb | 8 + spec/factories/sermon_series.rb | 8 + spec/factories/sermon_topics.rb | 8 + spec/factories/{resources.rb => sermons.rb} | 3 +- spec/factories/steps.rb | 9 - spec/features/active_admin_smoke_spec.rb | 39 +--- spec/models/location/connection/step_spec.rb | 7 - spec/models/location/prayer_spec.rb | 7 - spec/models/location/service_spec.rb | 7 - .../models/resource/connection/author_spec.rb | 7 - .../resource/connection/scripture_spec.rb | 7 - .../models/resource/connection/series_spec.rb | 7 - spec/models/resource/connection/topic_spec.rb | 7 - ...resource_spec.rb => sermon_author_spec.rb} | 2 +- ...event_spec.rb => sermon_scripture_spec.rb} | 2 +- spec/models/sermon_series_spec.rb | 7 + spec/models/{step_spec.rb => sermon_spec.rb} | 2 +- ...{location_spec.rb => sermon_topic_spec.rb} | 2 +- spec/requests/resources_spec.rb | 4 +- 111 files changed, 556 insertions(+), 1342 deletions(-) delete mode 100644 app/admin/location_connection_steps.rb delete mode 100644 app/admin/location_events.rb delete mode 100644 app/admin/location_prayers.rb delete mode 100644 app/admin/location_services.rb delete mode 100644 app/admin/locations.rb delete mode 100644 app/admin/resource_articles.rb rename app/admin/{resource_sermons.rb => sermons.rb} (82%) delete mode 100644 app/admin/steps.rb delete mode 100644 app/constraints/resource_type_constraint.rb delete mode 100644 app/decorators/resource/article_decorator.rb delete mode 100644 app/decorators/resource/sermon_decorator.rb delete mode 100644 app/decorators/resource_decorator.rb create mode 100644 app/decorators/sermon_decorator.rb rename app/decorators/{resource/connection/scripture_decorator.rb => sermon_scripture_decorator.rb} (54%) delete mode 100644 app/graphql/queries/events_query.rb delete mode 100644 app/graphql/queries/locations_query.rb delete mode 100644 app/graphql/queries/prayers_query.rb rename app/graphql/queries/{resources_query.rb => sermons_query.rb} (76%) delete mode 100644 app/graphql/queries/steps_query.rb delete mode 100644 app/graphql/types/location/connection/step_type.rb delete mode 100644 app/graphql/types/location/event_type.rb delete mode 100644 app/graphql/types/location/prayer_type.rb delete mode 100644 app/graphql/types/location/service_type.rb delete mode 100644 app/graphql/types/location_type.rb rename app/graphql/types/{resource/connection/scripture_type.rb => sermon_scripture_type.rb} (52%) rename app/graphql/types/{resource_type.rb => sermon_type.rb} (91%) delete mode 100644 app/graphql/types/step_type.rb delete mode 100644 app/models/location.rb delete mode 100644 app/models/location/connection.rb delete mode 100644 app/models/location/connection/step.rb delete mode 100644 app/models/location/event.rb delete mode 100644 app/models/location/prayer.rb delete mode 100644 app/models/location/service.rb delete mode 100644 app/models/resource.rb delete mode 100644 app/models/resource/article.rb delete mode 100644 app/models/resource/connection.rb delete mode 100644 app/models/resource/connection/series.rb delete mode 100644 app/models/resource/sermon.rb create mode 100644 app/models/sermon.rb rename app/models/{resource/connection/author.rb => sermon_author.rb} (53%) rename app/models/{resource/connection/scripture.rb => sermon_scripture.rb} (75%) create mode 100644 app/models/sermon_series.rb rename app/models/{resource/connection/topic.rb => sermon_topic.rb} (57%) delete mode 100644 app/models/step.rb create mode 100644 db/migrate/20260328000000_simplify_resources_to_sermons.rb delete mode 100644 spec/factories/location/connection/steps.rb delete mode 100644 spec/factories/location/events.rb delete mode 100644 spec/factories/location/prayers.rb delete mode 100644 spec/factories/location/services.rb delete mode 100644 spec/factories/locations.rb delete mode 100644 spec/factories/resource/connection/authors.rb delete mode 100644 spec/factories/resource/connection/scriptures.rb delete mode 100644 spec/factories/resource/connection/series.rb delete mode 100644 spec/factories/resource/connection/topics.rb create mode 100644 spec/factories/sermon_authors.rb create mode 100644 spec/factories/sermon_scriptures.rb create mode 100644 spec/factories/sermon_series.rb create mode 100644 spec/factories/sermon_topics.rb rename spec/factories/{resources.rb => sermons.rb} (84%) delete mode 100644 spec/factories/steps.rb delete mode 100644 spec/models/location/connection/step_spec.rb delete mode 100644 spec/models/location/prayer_spec.rb delete mode 100644 spec/models/location/service_spec.rb delete mode 100644 spec/models/resource/connection/author_spec.rb delete mode 100644 spec/models/resource/connection/scripture_spec.rb delete mode 100644 spec/models/resource/connection/series_spec.rb delete mode 100644 spec/models/resource/connection/topic_spec.rb rename spec/models/{resource_spec.rb => sermon_author_spec.rb} (78%) rename spec/models/{location/event_spec.rb => sermon_scripture_spec.rb} (77%) create mode 100644 spec/models/sermon_series_spec.rb rename spec/models/{step_spec.rb => sermon_spec.rb} (82%) rename spec/models/{location_spec.rb => sermon_topic_spec.rb} (79%) diff --git a/app/admin/location_connection_steps.rb b/app/admin/location_connection_steps.rb deleted file mode 100644 index 65f6ef6..0000000 --- a/app/admin/location_connection_steps.rb +++ /dev/null @@ -1,26 +0,0 @@ -# frozen_string_literal: true - -ActiveAdmin.register Location::Connection::Step do - menu parent: 'Locations', label: 'Steps' - permit_params :content, - :elvanto_form_id, - :mail_chimp_user_id, - :mail_chimp_audience_id, - :location_id, - :step_id, - :fluro_form_url - - form do |f| - f.semantic_errors - inputs do - f.input :location - f.input :step - f.input :content, as: :text - f.input :elvanto_form_id - f.input :mail_chimp_user_id - f.input :mail_chimp_audience_id - f.input :fluro_form_url - end - f.actions - end -end diff --git a/app/admin/location_events.rb b/app/admin/location_events.rb deleted file mode 100644 index 7ab1ddd..0000000 --- a/app/admin/location_events.rb +++ /dev/null @@ -1,53 +0,0 @@ -# frozen_string_literal: true - -ActiveAdmin.register Location::Event do - menu parent: 'Locations', label: 'Events' - permit_params :banner, :name, :content, :start_at, :end_at, :address, :elvanto_form_id, :facebook_url, :location_id, - :registration_url - - scope :upcoming, default: true - scope :featured - scope :all - - batch_action :feature do |ids| - batch_action_collection.find(ids).each do |event| - event.update(featured_at: Time.zone.now) - end - redirect_to collection_path, success: 'The event(s) have been featured' - end - - batch_action :unfeature do |ids| - batch_action_collection.find(ids).each do |event| - event.update(featured_at: nil) - end - redirect_to collection_path, warning: 'The event(s) have been unfeatured' - end - - index do - selectable_column - column :name - column :location - column :address - column :start_at - column :end_at - column :featured_at - actions - end - - form do |f| - f.semantic_errors - inputs do - f.input :name - f.input :banner, as: :file - f.input :content, as: :trix - f.input :location - f.input :start_at, as: :date_time_picker - f.input :end_at, as: :date_time_picker - f.input :address - f.input :elvanto_form_id - f.input :registration_url - f.input :facebook_url - end - f.actions - end -end diff --git a/app/admin/location_prayers.rb b/app/admin/location_prayers.rb deleted file mode 100644 index 16fcceb..0000000 --- a/app/admin/location_prayers.rb +++ /dev/null @@ -1,18 +0,0 @@ -# frozen_string_literal: true - -ActiveAdmin.register Location::Prayer do - menu parent: 'Locations', label: 'Prayers' - permit_params :banner, :name, :snippet, :content, :location_id - - form do |f| - f.semantic_errors - inputs do - f.input :name - f.input :banner, as: :file - f.input :snippet - f.input :content, as: :text - f.input :location - end - f.actions - end -end diff --git a/app/admin/location_services.rb b/app/admin/location_services.rb deleted file mode 100644 index 28f0a60..0000000 --- a/app/admin/location_services.rb +++ /dev/null @@ -1,17 +0,0 @@ -# frozen_string_literal: true - -ActiveAdmin.register Location::Service do - menu parent: 'Locations', label: 'Services' - permit_params :start_at, :end_at, :location_id, :elvanto_form_id - - form do |f| - f.semantic_errors - inputs do - f.input :start_at, as: :date_time_picker - f.input :end_at, as: :date_time_picker - f.input :location - f.input :elvanto_form_id - end - f.actions - end -end diff --git a/app/admin/locations.rb b/app/admin/locations.rb deleted file mode 100644 index 995838d..0000000 --- a/app/admin/locations.rb +++ /dev/null @@ -1,22 +0,0 @@ -# frozen_string_literal: true - -ActiveAdmin.register Location do - permit_params :name, :snippet, :content, :address, :banner - - filter :name - filter :snippet - filter :content - filter :address - - form do |f| - f.semantic_errors - inputs do - f.input :name - f.input :banner, as: :file - f.input :snippet - f.input :content, as: :text - f.input :address - end - f.actions - end -end diff --git a/app/admin/resource_articles.rb b/app/admin/resource_articles.rb deleted file mode 100644 index 81e3c35..0000000 --- a/app/admin/resource_articles.rb +++ /dev/null @@ -1,44 +0,0 @@ -# frozen_string_literal: true - -ActiveAdmin.register Resource::Article do - menu parent: 'Resources', label: 'Articles' - config.sort_order = 'published_at_desc' - - permit_params :name, :snippet, :content, :banner, :published_at, :featured_at, - topic_ids: [], author_ids: [], scripture_ids: [], series_ids: [] - - filter :name - filter :snippet - filter :content - filter :published_at - filter :featured_at - filter :author - filter :scripture - filter :series - filter :topic - - index do - id_column - column :name - column :published_at - column :featured_at - actions - end - - form do |f| - f.semantic_errors - inputs do - f.input :name - f.input :published_at, as: :date_time_picker - f.input :featured_at, as: :date_time_picker - f.input :snippet - f.input :content, as: :text - f.input :banner, as: :file - f.input :topics, collection: Category::Topic.all, multiple: true, input_html: { class: 'chosen-select' } - f.input :authors, collection: Author.all, multiple: true, input_html: { class: 'chosen-select' } - f.input :scriptures, collection: Scripture.all, multiple: true - f.input :series, collection: Series.all, multiple: true, input_html: { class: 'chosen-select' } - end - f.actions - end -end diff --git a/app/admin/resource_sermons.rb b/app/admin/sermons.rb similarity index 82% rename from app/admin/resource_sermons.rb rename to app/admin/sermons.rb index 33c602a..45a85a5 100644 --- a/app/admin/resource_sermons.rb +++ b/app/admin/sermons.rb @@ -1,8 +1,8 @@ # frozen_string_literal: true # rubocop:disable Metrics/BlockLength -ActiveAdmin.register Resource::Sermon do - menu parent: 'Resources', label: 'Sermons' +ActiveAdmin.register Sermon do + menu label: 'Sermons' config.sort_order = 'published_at_desc' order_by :published_at do |order_clause| @@ -12,7 +12,7 @@ permit_params :name, :snippet, :content, :video, :audio, :youtube_url, :audio_url, :published_at, :featured_at, :sermon_notes, :connect_group_notes, topic_ids: [], author_ids: [], scripture_ids: [], series_ids: [], - connection_scriptures_attributes: %i[id resource_id scripture_id range _destroy] + sermon_scriptures_attributes: %i[id sermon_id scripture_id range _destroy] filter :name filter :snippet @@ -22,12 +22,12 @@ filter :series, collection: proc { Series.order(:name).all } batch_action :publish do |ids| - Resource::Sermon.batch_publish(ids) + Sermon.batch_publish(ids) redirect_to collection_path, notice: "#{ids.size} sermon(s) published" end batch_action :unpublish do |ids| - Resource::Sermon.batch_unpublish(ids) + Sermon.batch_unpublish(ids) redirect_to collection_path, notice: "#{ids.size} sermon(s) unpublished" end @@ -54,7 +54,7 @@ f.input :audio, as: :file f.input :topics, collection: Category::Topic.all, multiple: true f.input :authors, collection: Author.all, multiple: true - f.has_many :connection_scriptures, heading: 'Bible Passage', new_record: 'Add Passage Range' do |a| + f.has_many :sermon_scriptures, heading: 'Bible Passage', new_record: 'Add Passage Range' do |a| a.input :scripture, collection: Scripture.all, label: 'Book' a.input :range end diff --git a/app/admin/steps.rb b/app/admin/steps.rb deleted file mode 100644 index 2044c4c..0000000 --- a/app/admin/steps.rb +++ /dev/null @@ -1,63 +0,0 @@ -# frozen_string_literal: true - -ActiveAdmin.register Step do - permit_params :name, :content, :banner - config.sort_order = 'position_asc' - - scope :featured - scope :all, default: true - - filter :name - filter :created_at - filter :updated_at - - batch_action :feature do |ids| - batch_action_collection.find(ids).each do |step| - step.update(featured_at: Time.zone.now) - end - redirect_to collection_path, alert: 'The step(s) have been featured' - end - - batch_action :unfeature do |ids| - batch_action_collection.find(ids).each do |event| - event.update(featured_at: nil) - end - redirect_to collection_path, warning: 'The step(s) have been unfeatured' - end - - index do - selectable_column - column do |post| - [ - link_to(icon('chevron-up', 'font-awesome'), move_higher_admin_step_path(post)), - link_to(icon('chevron-down', 'font-awesome'), move_lower_admin_step_path(post)) - ].join(' ').html_safe - end - column :position - column :name - column :featured_at - actions - end - - member_action :move_higher, method: :get do - flash[:notice] = "#{resource.name} moved higher" - resource.move_higher - redirect_to action: :index - end - - member_action :move_lower, method: :get do - flash[:notice] = "#{resource.name} moved lower" - resource.move_lower - redirect_to action: :index - end - - form do |f| - f.semantic_errors - inputs do - f.input :name - f.input :banner, as: :file - f.input :content, as: :text - end - f.actions - end -end diff --git a/app/constraints/resource_type_constraint.rb b/app/constraints/resource_type_constraint.rb deleted file mode 100644 index 84b7aea..0000000 --- a/app/constraints/resource_type_constraint.rb +++ /dev/null @@ -1,7 +0,0 @@ -# frozen_string_literal: true - -class ResourceTypeConstraint - def matches?(request) - request.params[:resource_type].blank? || Resource::TYPES.keys.include?(request.params[:resource_type].to_sym) - end -end diff --git a/app/controllers/resources/authors_controller.rb b/app/controllers/resources/authors_controller.rb index 8bac777..2db590c 100644 --- a/app/controllers/resources/authors_controller.rb +++ b/app/controllers/resources/authors_controller.rb @@ -17,10 +17,7 @@ def show def load_resources return @resources if @resources - @resources = Resource.order(published_at: :desc).joins(:authors).where(authors: { id: [@author.id] }) - if params[:resource_type].present? - @resources = @resources.where(type: Resource::TYPES[params[:resource_type].to_sym]) - end + @resources = Sermon.order(published_at: :desc).joins(:authors).where(authors: { id: [@author.id] }) @resources = @resources.published.page params[:page] end @@ -43,8 +40,6 @@ def alphabetized_authors end def scope - return ::Author unless params[:resource_type] - - ::Author.joins(:resources).where(resources: { type: Resource::TYPES[params[:resource_type].to_sym] }).distinct + ::Author end end diff --git a/app/controllers/resources/scriptures_controller.rb b/app/controllers/resources/scriptures_controller.rb index 58879e6..a67c4ca 100644 --- a/app/controllers/resources/scriptures_controller.rb +++ b/app/controllers/resources/scriptures_controller.rb @@ -17,10 +17,7 @@ def show def load_resources return @resources if @resources - @resources = Resource.order(published_at: :desc).joins(:scriptures).where(scriptures: { id: [@scripture.id] }) - if params[:resource_type].present? - @resources = @resources.where(type: Resource::TYPES[params[:resource_type].to_sym]) - end + @resources = Sermon.order(published_at: :desc).joins(:scriptures).where(scriptures: { id: [@scripture.id] }) @resources = @resources.published.page params[:page] end @@ -43,8 +40,6 @@ def alphabetized_scripture end def scope - return ::Scripture unless params[:resource_type] - - ::Scripture.joins(:resources).where(resources: { type: Resource::TYPES[params[:resource_type].to_sym] }).distinct + ::Scripture end end diff --git a/app/controllers/resources/series_controller.rb b/app/controllers/resources/series_controller.rb index c25d4e6..ae95f24 100644 --- a/app/controllers/resources/series_controller.rb +++ b/app/controllers/resources/series_controller.rb @@ -17,10 +17,7 @@ def show def load_resources return @resources if @resources - @resources = Resource.order(published_at: :desc).joins(:series).where(series: { id: [@series.id] }) - if params[:resource_type].present? - @resources = @resources.where(type: Resource::TYPES[params[:resource_type].to_sym]) - end + @resources = Sermon.order(published_at: :desc).joins(:series).where(series: { id: [@series.id] }) @resources = @resources.published.page params[:page] end @@ -43,8 +40,6 @@ def alphabetized_series end def scope - return ::Series unless params[:resource_type] - - ::Series.joins(:resources).where(resources: { type: Resource::TYPES[params[:resource_type].to_sym] }).distinct + ::Series end end diff --git a/app/controllers/resources/topics_controller.rb b/app/controllers/resources/topics_controller.rb index 22cb289..e2625f8 100644 --- a/app/controllers/resources/topics_controller.rb +++ b/app/controllers/resources/topics_controller.rb @@ -17,10 +17,7 @@ def show def load_resources return @resources if @resources - @resources = Resource.order(published_at: :desc).joins(:topics).where(category_topics: { id: [@topic.id] }) - if params[:resource_type].present? - @resources = @resources.where(type: Resource::TYPES[params[:resource_type].to_sym]) - end + @resources = Sermon.order(published_at: :desc).joins(:topics).where(category_topics: { id: [@topic.id] }) @resources = @resources.published.page params[:page] end @@ -33,18 +30,10 @@ def load_topic end def category_scope - return ::Category.joins(topics: :resources).distinct unless params[:resource_type] - - ::Category.joins(topics: :resources).where( - resources: { type: Resource::TYPES[params[:resource_type].to_sym] } - ).distinct + ::Category.joins(topics: :sermons).distinct end def scope - return ::Category::Topic unless params[:resource_type] - - ::Category::Topic.joins(:resources).where( - resources: { type: Resource::TYPES[params[:resource_type].to_sym] } - ).distinct + ::Category::Topic end end diff --git a/app/controllers/resources_controller.rb b/app/controllers/resources_controller.rb index f277594..d2c5d3c 100644 --- a/app/controllers/resources_controller.rb +++ b/app/controllers/resources_controller.rb @@ -20,9 +20,6 @@ def load_resources return @resources if @resources @resources = scope.order(published_at: :desc).published - if params[:resource_type].present? - @resources = @resources.where(type: Resource::TYPES[params[:resource_type].to_sym]) - end @resources = @resources.page params[:page] end @@ -31,7 +28,7 @@ def load_resource end def scope - ::Resource + ::Sermon end def render_rss_feed @@ -39,15 +36,12 @@ def render_rss_feed latest_update = resource_scope.maximum(:updated_at) cache_key_parts = %w[v1 rss resources] - if params[:resource_type].present? && Resource::TYPES.key?(params[:resource_type].to_sym) - cache_key_parts << params[:resource_type] - end cache_key_parts << latest_update.utc.to_fs(:number) if latest_update response.headers['Content-Type'] = 'application/rss+xml; charset=utf-8' cached_rss_content = Rails.cache.fetch(cache_key_parts.compact.join('/'), expires_in: 1.day) do - @resources = resource_scope.includes(:authors, :connection_scriptures) + @resources = resource_scope.includes(:authors, :sermon_scriptures) render_to_string template: 'resources/index', formats: [:rss] end @@ -55,10 +49,6 @@ def render_rss_feed end def rss_resources_scope - resources = scope.order(published_at: :desc).published - if params[:resource_type].present? && Resource::TYPES.key?(params[:resource_type].to_sym) - resources = resources.where(type: Resource::TYPES[params[:resource_type].to_sym]) - end - resources + scope.order(published_at: :desc).published end end diff --git a/app/decorators/resource/article_decorator.rb b/app/decorators/resource/article_decorator.rb deleted file mode 100644 index 0e3265d..0000000 --- a/app/decorators/resource/article_decorator.rb +++ /dev/null @@ -1,7 +0,0 @@ -# frozen_string_literal: true - -class Resource::ArticleDecorator < ResourceDecorator - def action - 'read' - end -end diff --git a/app/decorators/resource/sermon_decorator.rb b/app/decorators/resource/sermon_decorator.rb deleted file mode 100644 index d25e629..0000000 --- a/app/decorators/resource/sermon_decorator.rb +++ /dev/null @@ -1,15 +0,0 @@ -# frozen_string_literal: true - -class Resource::SermonDecorator < ResourceDecorator - def banner - object.banner.presence || object.series.first&.banner - end - - def foreground - object.foreground.presence || object.series.first&.foreground - end - - def background - object.background.presence || object.series.first&.background - end -end diff --git a/app/decorators/resource_decorator.rb b/app/decorators/resource_decorator.rb deleted file mode 100644 index a4a57d3..0000000 --- a/app/decorators/resource_decorator.rb +++ /dev/null @@ -1,49 +0,0 @@ -# frozen_string_literal: true - -class ResourceDecorator < ApplicationDecorator - decorates_association :connection_scriptures - decorates_association :authors - - def action - 'view' - end - - def type_title - type_param.titleize - end - - def type_param - type.demodulize.downcase - end - - def related - resources = related_resource_scope - resources = resources.where(series: { id: resource.series.pluck(:id) }) - resources = resources.or(resources.where(category_topics: { id: resource.topics.pluck(:id) })) - resources = resources.or(resources.where(authors: { id: resource.authors.pluck(:id) })) - resources = resources.or(resources.where(scriptures: { id: resource.scriptures.pluck(:id) })) - resources.decorate - end - - def description - return snippet if snippet.present? - - author_names = authors.map(&:name).join(', ') - scripture_names = connection_scriptures.map(&:name).join(', ') - display_published_at = published_at.strftime('%b %d, %Y') - - [author_names, scripture_names, display_published_at].compact_blank.join(' | ') - end - - def author_names - resource.authors.map(&:name).join(', ') - end - - def related_resource_scope - Resource.published - .order('RANDOM()') - .limit(3) - .left_outer_joins(:series, :authors, :topics, :scriptures) - .where.not(id: id) - end -end diff --git a/app/decorators/sermon_decorator.rb b/app/decorators/sermon_decorator.rb new file mode 100644 index 0000000..f611785 --- /dev/null +++ b/app/decorators/sermon_decorator.rb @@ -0,0 +1,61 @@ +# frozen_string_literal: true + +class SermonDecorator < ApplicationDecorator + decorates_association :sermon_scriptures + decorates_association :authors + + def action + 'view' + end + + def type_title + 'Sermon' + end + + def type_param + 'sermon' + end + + def banner + object.banner.presence || object.series.first&.banner + end + + def foreground + object.foreground.presence || object.series.first&.foreground + end + + def background + object.background.presence || object.series.first&.background + end + + def related + sermons = related_sermon_scope + sermons = sermons.where(series: { id: object.series.pluck(:id) }) + sermons = sermons.or(sermons.where(category_topics: { id: object.topics.pluck(:id) })) + sermons = sermons.or(sermons.where(authors: { id: object.authors.pluck(:id) })) + sermons = sermons.or(sermons.where(scriptures: { id: object.scriptures.pluck(:id) })) + sermons.decorate + end + + def description + return snippet if snippet.present? + + author_names = authors.map(&:name).join(', ') + scripture_names = sermon_scriptures.map(&:name).join(', ') + display_published_at = published_at.strftime('%b %d, %Y') + + [author_names, scripture_names, display_published_at].compact_blank.join(' | ') + end + + def author_names + object.authors.map(&:name).join(', ') + end + + def related_sermon_scope + Sermon.published + .order('RANDOM()') + .limit(3) + .left_outer_joins(:series, :authors, :topics, :scriptures) + .where.not(id: id) + end +end diff --git a/app/decorators/resource/connection/scripture_decorator.rb b/app/decorators/sermon_scripture_decorator.rb similarity index 54% rename from app/decorators/resource/connection/scripture_decorator.rb rename to app/decorators/sermon_scripture_decorator.rb index e088ab0..ba8ed10 100644 --- a/app/decorators/resource/connection/scripture_decorator.rb +++ b/app/decorators/sermon_scripture_decorator.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -class Resource::Connection::ScriptureDecorator < ApplicationDecorator +class SermonScriptureDecorator < ApplicationDecorator def name "#{scripture.name} #{range}" end diff --git a/app/graphql/queries/authors_query.rb b/app/graphql/queries/authors_query.rb index 4da73ad..0f63336 100644 --- a/app/graphql/queries/authors_query.rb +++ b/app/graphql/queries/authors_query.rb @@ -2,17 +2,8 @@ class Queries::AuthorsQuery < Queries::BaseQuery type Types::AuthorType.connection_type, null: false - argument :resource_type, String, required: false - def resolve(resource_type: nil) - scope(resource_type).all - end - - protected - - def scope(resource_type) - return ::Author if resource_type.blank? - - ::Author.joins(:resources).where(resources: { type: Resource::TYPES[resource_type.to_sym] }).distinct + def resolve + ::Author.joins(:sermons).distinct end end diff --git a/app/graphql/queries/categories_query.rb b/app/graphql/queries/categories_query.rb index 7329b34..7be9e86 100644 --- a/app/graphql/queries/categories_query.rb +++ b/app/graphql/queries/categories_query.rb @@ -2,17 +2,8 @@ class Queries::CategoriesQuery < Queries::BaseQuery type Types::CategoryType.connection_type, null: false - argument :resource_type, String, required: false - def resolve(resource_type: nil) - scope(resource_type).all - end - - protected - - def scope(resource_type) - return ::Category if resource_type.blank? - - ::Category.joins(:resources).where(resources: { type: Resource::TYPES[resource_type.to_sym] }).distinct + def resolve + ::Category.joins(topics: :sermons).distinct end end diff --git a/app/graphql/queries/events_query.rb b/app/graphql/queries/events_query.rb deleted file mode 100644 index fdf83bb..0000000 --- a/app/graphql/queries/events_query.rb +++ /dev/null @@ -1,30 +0,0 @@ -# frozen_string_literal: true - -class Queries::EventsQuery < Queries::BaseQuery - type Types::Location::EventType.connection_type, null: false - argument :featured, Boolean, required: false - argument :ids, [ID], required: false - argument :location_ids, [ID], required: false - - def resolve(ids: nil, location_ids: nil, featured: false) - scope(ids, location_ids, featured).all - end - - protected - - def scope(ids, location_ids, featured) - scope = ::Location::Event.upcoming - scope = filter_by_ids(scope, ids) - scope = filter_by_locations(scope, location_ids) - - featured ? scope.featured : scope - end - - def filter_by_ids(scope, ids) - ids.present? ? scope.where(id: ids) : scope - end - - def filter_by_locations(scope, ids) - ids.present? ? scope.where(location_id: ids) : scope - end -end diff --git a/app/graphql/queries/locations_query.rb b/app/graphql/queries/locations_query.rb deleted file mode 100644 index 3cde40e..0000000 --- a/app/graphql/queries/locations_query.rb +++ /dev/null @@ -1,21 +0,0 @@ -# frozen_string_literal: true - -class Queries::LocationsQuery < Queries::BaseQuery - type Types::LocationType.connection_type, null: false - argument :ids, [ID], required: false - - def resolve(ids: nil) - scope(ids).all - end - - protected - - def scope(ids) - scope = ::Location - filter_by_ids(scope, ids) - end - - def filter_by_ids(scope, ids) - ids.present? ? scope.where(id: ids) : scope - end -end diff --git a/app/graphql/queries/prayers_query.rb b/app/graphql/queries/prayers_query.rb deleted file mode 100644 index 043fc7b..0000000 --- a/app/graphql/queries/prayers_query.rb +++ /dev/null @@ -1,27 +0,0 @@ -# frozen_string_literal: true - -class Queries::PrayersQuery < Queries::BaseQuery - type Types::Location::PrayerType.connection_type, null: false - argument :ids, [ID], required: false - argument :location_ids, [ID], required: false - - def resolve(ids: nil, location_ids: nil) - scope(ids, location_ids).all - end - - protected - - def scope(ids, location_ids) - scope = ::Location::Prayer - scope = filter_by_ids(scope, ids) - filter_by_locations(scope, location_ids) - end - - def filter_by_ids(scope, ids) - ids.present? ? scope.where(id: ids) : scope - end - - def filter_by_locations(scope, ids) - ids.present? ? scope.where(location_id: ids) : scope - end -end diff --git a/app/graphql/queries/scriptures_query.rb b/app/graphql/queries/scriptures_query.rb index 7a5cd69..5385b86 100644 --- a/app/graphql/queries/scriptures_query.rb +++ b/app/graphql/queries/scriptures_query.rb @@ -2,17 +2,8 @@ class Queries::ScripturesQuery < Queries::BaseQuery type Types::ScriptureType.connection_type, null: false - argument :resource_type, String, required: false - def resolve(resource_type: nil) - scope(resource_type).all - end - - protected - - def scope(resource_type) - return ::Scripture if resource_type.blank? - - ::Scripture.joins(:resources).where(resources: { type: Resource::TYPES[resource_type.to_sym] }).distinct + def resolve + ::Scripture.joins(:sermons).distinct end end diff --git a/app/graphql/queries/series_query.rb b/app/graphql/queries/series_query.rb index 9acdcbd..867ee81 100644 --- a/app/graphql/queries/series_query.rb +++ b/app/graphql/queries/series_query.rb @@ -3,24 +3,15 @@ class Queries::SeriesQuery < Queries::BaseQuery type Types::SeriesType.connection_type, null: false argument :ids, [ID], required: false, default_value: nil - argument :resource_type, String, required: false, default_value: nil - def resolve(ids:, resource_type:) - scope(ids, resource_type).all.uniq + def resolve(ids:) + scope(ids).all.uniq end protected - def scope(ids, resource_type) - scope = ::Series.joins(:resources).where.not(resources: { published_at: nil }).order('resources.published_at desc') - - scope = filter_by_ids(scope, ids) - scope.where(resources: { type: Resource::TYPES[resource_type.to_sym] }) if resource_type.present? - - scope - end - - def filter_by_ids(scope, ids) + def scope(ids) + scope = ::Series.joins(:sermons).merge(Sermon.published).order('sermons.published_at desc') ids.present? ? scope.where(id: ids) : scope end end diff --git a/app/graphql/queries/resources_query.rb b/app/graphql/queries/sermons_query.rb similarity index 76% rename from app/graphql/queries/resources_query.rb rename to app/graphql/queries/sermons_query.rb index a5de4be..5dd5fce 100644 --- a/app/graphql/queries/resources_query.rb +++ b/app/graphql/queries/sermons_query.rb @@ -1,33 +1,29 @@ # frozen_string_literal: true -class Queries::ResourcesQuery < Queries::BaseQuery - type Types::ResourceType.connection_type, null: false +class Queries::SermonsQuery < Queries::BaseQuery + type Types::SermonType.connection_type, null: false argument :author_ids, [ID], required: false, default_value: nil argument :category_ids, [ID], required: false, default_value: nil argument :ids, [ID], required: false, default_value: nil - argument :resource_type, String, required: false, default_value: nil argument :scripture_ids, [ID], required: false, default_value: nil argument :series_ids, [ID], required: false, default_value: nil argument :topic_ids, [ID], required: false, default_value: nil - def resolve(ids:, author_ids:, category_ids:, scripture_ids:, series_ids:, topic_ids:, resource_type:) - scope(ids, author_ids, category_ids, scripture_ids, series_ids, topic_ids, resource_type).all + def resolve(ids:, author_ids:, category_ids:, scripture_ids:, series_ids:, topic_ids:) + scope(ids, author_ids, category_ids, scripture_ids, series_ids, topic_ids).all end protected - def scope(ids, author_ids, category_ids, scripture_ids, series_ids, topic_ids, resource_type) - scope = ::Resource.published.order(published_at: :desc) + def scope(ids, author_ids, category_ids, scripture_ids, series_ids, topic_ids) + scope = ::Sermon.published.order(published_at: :desc) scope = filter_by_ids(scope, ids) scope = filter_by_authors(scope, author_ids) scope = filter_by_categories(scope, category_ids) scope = filter_by_scriptures(scope, scripture_ids) scope = filter_by_series(scope, series_ids) - scope = filter_by_topics(scope, topic_ids) - scope = scope.where(type: Resource::TYPES[resource_type.to_sym]) if resource_type.present? - - scope + filter_by_topics(scope, topic_ids) end def filter_by_ids(scope, ids) diff --git a/app/graphql/queries/steps_query.rb b/app/graphql/queries/steps_query.rb deleted file mode 100644 index ffdb6f4..0000000 --- a/app/graphql/queries/steps_query.rb +++ /dev/null @@ -1,34 +0,0 @@ -# frozen_string_literal: true - -class Queries::StepsQuery < Queries::BaseQuery - type Types::StepType.connection_type, null: false - argument :featured, Boolean, required: false - argument :ids, [ID], required: false - argument :location_ids, [ID], required: false - - def resolve(ids: nil, location_ids: nil, featured: false) - scope(ids, location_ids, featured).all - end - - protected - - def scope(ids, location_ids, featured) - scope = ::Step.order(position: :asc) - scope = filter_by_ids(scope, ids) - scope = filter_by_locations(scope, location_ids) - - featured ? scope.featured : scope - end - - def filter_by_ids(scope, ids) - ids.present? ? scope.where(id: ids) : scope - end - - def filter_by_locations(scope, ids) - if ids.present? - scope.joins(:location_connection_steps).where(location_connection_steps: { location_id: ids }) - else - scope - end - end -end diff --git a/app/graphql/queries/topic_query.rb b/app/graphql/queries/topic_query.rb index d51ac2e..7d0f119 100644 --- a/app/graphql/queries/topic_query.rb +++ b/app/graphql/queries/topic_query.rb @@ -2,17 +2,8 @@ class Queries::TopicQuery < Queries::BaseQuery type Types::TopicType.connection_type, null: false - argument :resource_type, String, required: false - def resolve(resource_type: nil) - scope(resource_type).all - end - - protected - - def scope(resource_type) - return ::Category::Topic if resource_type.blank? - - ::Category::Topic.joins(:resources).where(resources: { type: Resource::TYPES[resource_type.to_sym] }).distinct + def resolve + ::Category::Topic.joins(:sermons).distinct end end diff --git a/app/graphql/types/location/connection/step_type.rb b/app/graphql/types/location/connection/step_type.rb deleted file mode 100644 index 8414759..0000000 --- a/app/graphql/types/location/connection/step_type.rb +++ /dev/null @@ -1,14 +0,0 @@ -# frozen_string_literal: true - -class Types::Location::Connection::StepType < Types::BaseObject - graphql_name 'LocationConnectionStepType' - - field :content, String, null: true - field :elvanto_form_id, String, null: true - field :fluro_form_url, String, null: true - field :id, ID, null: false - field :location, Types::LocationType, null: false - field :mail_chimp_audience_id, String, null: true - field :mail_chimp_user_id, String, null: true - field :step, Types::StepType, null: false -end diff --git a/app/graphql/types/location/event_type.rb b/app/graphql/types/location/event_type.rb deleted file mode 100644 index 4a31f0c..0000000 --- a/app/graphql/types/location/event_type.rb +++ /dev/null @@ -1,25 +0,0 @@ -# frozen_string_literal: true - -class Types::Location::EventType < Types::BaseObject - include Rails.application.routes.url_helpers - - field :address, String, null: false - field :banner_url, String, null: false - field :content, String, null: false - field :elvanto_form_id, String, null: true - field :end_at, GraphQL::Types::ISO8601DateTime, null: false - field :facebook_url, String, null: true - field :id, ID, null: false - field :location, Types::LocationType, null: false - field :name, String, null: false - field :registration_url, String, null: true - field :start_at, GraphQL::Types::ISO8601DateTime, null: false - - def banner_url - polymorphic_url( - object.banner.variant( - convert: 'jpg', saver: { quality: 80 }, strip: true, resize_to_limit: [1920, 1080] - ) - ) - end -end diff --git a/app/graphql/types/location/prayer_type.rb b/app/graphql/types/location/prayer_type.rb deleted file mode 100644 index ea82f07..0000000 --- a/app/graphql/types/location/prayer_type.rb +++ /dev/null @@ -1,20 +0,0 @@ -# frozen_string_literal: true - -class Types::Location::PrayerType < Types::BaseObject - include Rails.application.routes.url_helpers - - field :banner_url, String, null: false - field :content, String, null: true - field :id, ID, null: false - field :location, Types::LocationType, null: false - field :name, String, null: false - field :snippet, String, null: false - - def banner_url - polymorphic_url( - object.banner.variant( - convert: 'jpg', saver: { quality: 80 }, strip: true, resize_to_limit: [1920, 1080] - ) - ) - end -end diff --git a/app/graphql/types/location/service_type.rb b/app/graphql/types/location/service_type.rb deleted file mode 100644 index 2bcec77..0000000 --- a/app/graphql/types/location/service_type.rb +++ /dev/null @@ -1,9 +0,0 @@ -# frozen_string_literal: true - -class Types::Location::ServiceType < Types::BaseObject - field :elvanto_form_id, String, null: true - field :end_at, String, null: false - field :id, ID, null: false - field :location, Types::LocationType, null: false - field :start_at, String, null: false -end diff --git a/app/graphql/types/location_type.rb b/app/graphql/types/location_type.rb deleted file mode 100644 index 69ab837..0000000 --- a/app/graphql/types/location_type.rb +++ /dev/null @@ -1,24 +0,0 @@ -# frozen_string_literal: true - -class Types::LocationType < Types::BaseObject - include Rails.application.routes.url_helpers - - field :address, String, null: false - field :banner_url, String, null: false - field :content, String, null: true - field :events, Types::Location::EventType.connection_type, null: false - field :id, ID, null: false - field :location_connection_steps, Types::Location::Connection::StepType.connection_type, null: false - field :name, String, null: false - field :prayers, Types::Location::PrayerType.connection_type, null: false - field :services, Types::Location::ServiceType.connection_type, null: false - field :snippet, String, null: false - - def banner_url - polymorphic_url( - object.banner.variant( - convert: 'jpg', saver: { quality: 80 }, strip: true, resize_to_limit: [1920, 1080] - ) - ) - end -end diff --git a/app/graphql/types/query_type.rb b/app/graphql/types/query_type.rb index 34b8861..e4c3c98 100644 --- a/app/graphql/types/query_type.rb +++ b/app/graphql/types/query_type.rb @@ -3,12 +3,8 @@ class Types::QueryType < Types::BaseObject field :authors, resolver: Queries::AuthorsQuery field :categories, resolver: Queries::CategoriesQuery - field :events, resolver: Queries::EventsQuery - field :locations, resolver: Queries::LocationsQuery - field :prayers, resolver: Queries::PrayersQuery - field :resources, resolver: Queries::ResourcesQuery field :scriptures, resolver: Queries::ScripturesQuery + field :sermons, resolver: Queries::SermonsQuery field :series, resolver: Queries::SeriesQuery - field :steps, resolver: Queries::StepsQuery field :topics, resolver: Queries::TopicQuery end diff --git a/app/graphql/types/resource/connection/scripture_type.rb b/app/graphql/types/sermon_scripture_type.rb similarity index 52% rename from app/graphql/types/resource/connection/scripture_type.rb rename to app/graphql/types/sermon_scripture_type.rb index 04d87ef..45ebcb5 100644 --- a/app/graphql/types/resource/connection/scripture_type.rb +++ b/app/graphql/types/sermon_scripture_type.rb @@ -1,11 +1,9 @@ # frozen_string_literal: true -class Types::Resource::Connection::ScriptureType < Types::BaseObject - graphql_name 'ResourceConnectionScriptureType' - +class Types::SermonScriptureType < Types::BaseObject field :content, String, null: false field :id, ID, null: false field :range, String, null: true - field :resource, Types::ResourceType, null: false + field :sermon, Types::SermonType, null: false field :scripture, Types::ScriptureType, null: false end diff --git a/app/graphql/types/resource_type.rb b/app/graphql/types/sermon_type.rb similarity index 91% rename from app/graphql/types/resource_type.rb rename to app/graphql/types/sermon_type.rb index 0e87f49..2e18f26 100644 --- a/app/graphql/types/resource_type.rb +++ b/app/graphql/types/sermon_type.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -class Types::ResourceType < Types::BaseObject +class Types::SermonType < Types::BaseObject include Rails.application.routes.url_helpers field :audio_url, String, null: true @@ -8,7 +8,7 @@ class Types::ResourceType < Types::BaseObject field :background_url, String, null: true field :banner_url, String, null: true field :connect_group_notes, String, null: true - field :connection_scriptures, [Types::Resource::Connection::ScriptureType], null: false + field :connection_scriptures, [Types::SermonScriptureType], null: false field :content, String, null: true field :foreground_url, String, null: true field :id, ID, null: false diff --git a/app/graphql/types/step_type.rb b/app/graphql/types/step_type.rb deleted file mode 100644 index 77fd86d..0000000 --- a/app/graphql/types/step_type.rb +++ /dev/null @@ -1,17 +0,0 @@ -# frozen_string_literal: true - -class Types::StepType < Types::BaseObject - include Rails.application.routes.url_helpers - - field :banner_url, String, null: false - field :content, String, null: true - field :id, ID, null: false - field :location_connection_steps, Types::Location::Connection::StepType.connection_type, null: false - field :name, String, null: false - - def banner_url - polymorphic_url( - object.banner.variant(convert: 'jpg', saver: { quality: 80 }, strip: true, resize_to_limit: [1920, 1080]) - ) - end -end diff --git a/app/models/author.rb b/app/models/author.rb index 78931df..ecf3957 100644 --- a/app/models/author.rb +++ b/app/models/author.rb @@ -4,14 +4,14 @@ class Author < ApplicationRecord extend FriendlyId friendly_id :name, use: :slugged - has_many :connection_authors, class_name: 'Resource::Connection::Author', dependent: :destroy - has_many :resources, through: :connection_authors + has_many :sermon_authors, dependent: :destroy + has_many :sermons, through: :sermon_authors validates :name, presence: true, uniqueness: true # Only allow these associations to be searchable by Ransack (used in ActiveAdmin filters) def self.ransackable_associations(_auth_object = nil) - %w[resources connection_authors] + %w[sermons sermon_authors] end def self.ransackable_attributes(_auth_object = nil) diff --git a/app/models/category/topic.rb b/app/models/category/topic.rb index dc2e402..a6533b6 100644 --- a/app/models/category/topic.rb +++ b/app/models/category/topic.rb @@ -4,15 +4,15 @@ class Category::Topic < ApplicationRecord extend FriendlyId friendly_id :name, use: :slugged - has_many :connection_topics, class_name: 'Resource::Connection::Topic', dependent: :destroy - has_many :resources, through: :connection_topics + has_many :sermon_topics, dependent: :destroy + has_many :sermons, through: :sermon_topics belongs_to :category validates :name, presence: true, uniqueness: true # Only allow these associations to be searchable by Ransack (used in ActiveAdmin filters) def self.ransackable_associations(_auth_object = nil) - %w[resources connection_topics] + %w[sermons sermon_topics] end def self.ransackable_attributes(_auth_object = nil) diff --git a/app/models/location.rb b/app/models/location.rb deleted file mode 100644 index 135c9ad..0000000 --- a/app/models/location.rb +++ /dev/null @@ -1,29 +0,0 @@ -# frozen_string_literal: true - -class Location < ApplicationRecord - has_many :events, dependent: :destroy - has_many :prayers, dependent: :destroy - has_many :services, dependent: :destroy - has_many :location_connection_steps, dependent: :destroy, class_name: 'Location::Connection::Step' - has_one_attached :banner - validates :name, :snippet, :content, :address, presence: true - validates :banner, - attached: true, - aspect_ratio: :is_16_9, - content_type: %r{\Aimage/.*\z}, - dimension: { - width: { in: 0..1920 }, - height: { in: 0..1080 }, - message: '1920x1080 max resolution' - }, - size: { less_than: 500.kilobytes, message: '500KB max size' } - - # No association filters in ActiveAdmin, so none are ransackable - def self.ransackable_associations(_auth_object = nil) - [] - end - - def self.ransackable_attributes(_auth_object = nil) - %w[address content created_at id name snippet updated_at] - end -end diff --git a/app/models/location/connection.rb b/app/models/location/connection.rb deleted file mode 100644 index d3b06a9..0000000 --- a/app/models/location/connection.rb +++ /dev/null @@ -1,7 +0,0 @@ -# frozen_string_literal: true - -module Location::Connection - def self.table_name_prefix - 'location_connection_' - end -end diff --git a/app/models/location/connection/step.rb b/app/models/location/connection/step.rb deleted file mode 100644 index bd4ee06..0000000 --- a/app/models/location/connection/step.rb +++ /dev/null @@ -1,15 +0,0 @@ -# frozen_string_literal: true - -class Location::Connection::Step < ApplicationRecord - belongs_to :step, class_name: '::Step' - belongs_to :location, class_name: '::Location' - - def self.ransackable_attributes(_auth_object = nil) - %w[created_at id location_id step_id updated_at elvanto_form_id content mail_chimp_user_id mail_chimp_audience_id - fluro_form_url] - end - - def self.ransackable_associations(_auth_object = nil) - %w[location step] - end -end diff --git a/app/models/location/event.rb b/app/models/location/event.rb deleted file mode 100644 index 2500d9f..0000000 --- a/app/models/location/event.rb +++ /dev/null @@ -1,29 +0,0 @@ -# frozen_string_literal: true - -class Location::Event < ApplicationRecord - belongs_to :location - has_one_attached :banner - validates :start_at, :end_at, :name, :content, :address, presence: true - validates :banner, - attached: true, - aspect_ratio: :is_16_9, - content_type: %r{\Aimage/.*\z}, - dimension: { - width: { in: 0..1920 }, - height: { in: 0..1080 }, - message: '1920x1080 max resolution' - }, - size: { less_than: 500.kilobytes, message: '500KB max size' } - validates :registration_url, :facebook_url, url: { allow_blank: true } - scope :upcoming, -> { where(end_at: Time.zone.today..).order(:start_at) } - scope :featured, -> { upcoming.where.not(featured_at: nil) } - - def self.ransackable_attributes(_auth_object = nil) - %w[created_at id location_id updated_at elvanto_form_id name content address start_at end_at featured_at - facebook_url registration_url] - end - - def self.ransackable_associations(_auth_object = nil) - %w[location banner_attachment banner_blob] - end -end diff --git a/app/models/location/prayer.rb b/app/models/location/prayer.rb deleted file mode 100644 index df2f36a..0000000 --- a/app/models/location/prayer.rb +++ /dev/null @@ -1,25 +0,0 @@ -# frozen_string_literal: true - -class Location::Prayer < ApplicationRecord - belongs_to :location - has_one_attached :banner - validates :name, :snippet, :content, presence: true - validates :banner, - attached: true, - aspect_ratio: :is_16_9, - content_type: %r{\Aimage/.*\z}, - dimension: { - width: { in: 0..1920 }, - height: { in: 0..1080 }, - message: '1920x1080 max resolution' - }, - size: { less_than: 500.kilobytes, message: '500KB max size' } - - def self.ransackable_attributes(_auth_object = nil) - %w[content created_at id location_id name snippet updated_at] - end - - def self.ransackable_associations(_auth_object = nil) - %w[location banner_attachment banner_blob] - end -end diff --git a/app/models/location/service.rb b/app/models/location/service.rb deleted file mode 100644 index 436d012..0000000 --- a/app/models/location/service.rb +++ /dev/null @@ -1,14 +0,0 @@ -# frozen_string_literal: true - -class Location::Service < ApplicationRecord - belongs_to :location - validates :start_at, :end_at, presence: true - - def self.ransackable_attributes(_auth_object = nil) - %w[created_at id location_id updated_at elvanto_form_id start_at end_at] - end - - def self.ransackable_associations(_auth_object = nil) - %w[location] - end -end diff --git a/app/models/resource.rb b/app/models/resource.rb deleted file mode 100644 index aff081e..0000000 --- a/app/models/resource.rb +++ /dev/null @@ -1,51 +0,0 @@ -# frozen_string_literal: true - -class Resource < ApplicationRecord - TYPES = { article: 'Resource::Article', sermon: 'Resource::Sermon' }.freeze - - TYPES.each do |key, value| - scope key.to_s.pluralize, -> { where(type: value) } - end - - extend FriendlyId - friendly_id :name, use: :slugged - - has_one_attached :banner - has_one_attached :foreground - has_one_attached :background - has_one_attached :audio - has_one_attached :video - - has_many :connection_authors, class_name: 'Resource::Connection::Author', dependent: :destroy - has_many :authors, through: :connection_authors - has_many :connection_scriptures, class_name: 'Resource::Connection::Scripture', dependent: :destroy - has_many :scriptures, through: :connection_scriptures - has_many :connection_series, class_name: 'Resource::Connection::Series', dependent: :destroy - has_many :series, through: :connection_series - has_many :connection_topics, class_name: 'Resource::Connection::Topic', dependent: :destroy - has_many :topics, through: :connection_topics - - accepts_nested_attributes_for :connection_scriptures - - validates :name, presence: true - - scope :published, -> { where.not(published_at: nil) } - scope :featured, -> { where.not(featured_at: nil) } - - def self.batch_publish(ids) - where(id: ids).find_each { |r| r.update(published_at: Time.zone.now) } - end - - def self.batch_unpublish(ids) - where(id: ids).find_each { |r| r.update(published_at: nil) } - end - - # Only allow these associations to be searchable by Ransack (used in ActiveAdmin filters) - def self.ransackable_associations(_auth_object = nil) - %w[authors scriptures series topics connection_authors connection_scriptures connection_series connection_topics] - end - - def self.ransackable_attributes(_auth_object = nil) - %w[created_at featured_at id name published_at slug type updated_at snippet content] - end -end diff --git a/app/models/resource/article.rb b/app/models/resource/article.rb deleted file mode 100644 index 355906b..0000000 --- a/app/models/resource/article.rb +++ /dev/null @@ -1,4 +0,0 @@ -# frozen_string_literal: true - -class Resource::Article < Resource -end diff --git a/app/models/resource/connection.rb b/app/models/resource/connection.rb deleted file mode 100644 index 2a686f8..0000000 --- a/app/models/resource/connection.rb +++ /dev/null @@ -1,7 +0,0 @@ -# frozen_string_literal: true - -module Resource::Connection - def self.table_name_prefix - 'resource_connection_' - end -end diff --git a/app/models/resource/connection/series.rb b/app/models/resource/connection/series.rb deleted file mode 100644 index 158fba1..0000000 --- a/app/models/resource/connection/series.rb +++ /dev/null @@ -1,14 +0,0 @@ -# frozen_string_literal: true - -class Resource::Connection::Series < ApplicationRecord - belongs_to :resource - belongs_to :series - - def self.ransackable_attributes(_auth_object = nil) - %w[created_at id resource_id series_id updated_at] - end - - def self.ransackable_associations(_auth_object = nil) - %w[resource series] # Added common associations, can be emptied if not needed for search - end -end diff --git a/app/models/resource/sermon.rb b/app/models/resource/sermon.rb deleted file mode 100644 index 9213d99..0000000 --- a/app/models/resource/sermon.rb +++ /dev/null @@ -1,4 +0,0 @@ -# frozen_string_literal: true - -class Resource::Sermon < Resource -end diff --git a/app/models/scripture.rb b/app/models/scripture.rb index c93751b..4dba1d0 100644 --- a/app/models/scripture.rb +++ b/app/models/scripture.rb @@ -4,14 +4,14 @@ class Scripture < ApplicationRecord extend FriendlyId friendly_id :name, use: :slugged - has_many :connection_scriptures, class_name: 'Resource::Connection::Scripture', dependent: :destroy - has_many :resources, through: :connection_scriptures + has_many :sermon_scriptures, dependent: :destroy + has_many :sermons, through: :sermon_scriptures validates :name, presence: true, uniqueness: true # Only allow these associations to be searchable by Ransack (used in ActiveAdmin filters) def self.ransackable_associations(_auth_object = nil) - %w[resources connection_scriptures] + %w[sermons sermon_scriptures] end def self.ransackable_attributes(_auth_object = nil) diff --git a/app/models/series.rb b/app/models/series.rb index 9761059..c0ceee5 100644 --- a/app/models/series.rb +++ b/app/models/series.rb @@ -4,8 +4,8 @@ class Series < ApplicationRecord extend FriendlyId friendly_id :name, use: :slugged - has_many :connection_series, class_name: 'Resource::Connection::Series', dependent: :destroy - has_many :resources, through: :connection_series + has_many :sermon_series, dependent: :destroy + has_many :sermons, through: :sermon_series validates :name, presence: true, uniqueness: true @@ -15,7 +15,7 @@ class Series < ApplicationRecord # Only allow these associations to be searchable by Ransack (used in ActiveAdmin filters) def self.ransackable_associations(_auth_object = nil) - %w[resources connection_series banner_attachment banner_blob foreground_attachment foreground_blob + %w[sermons sermon_series banner_attachment banner_blob foreground_attachment foreground_blob background_attachment background_blob] end diff --git a/app/models/sermon.rb b/app/models/sermon.rb new file mode 100644 index 0000000..a301755 --- /dev/null +++ b/app/models/sermon.rb @@ -0,0 +1,45 @@ +# frozen_string_literal: true + +class Sermon < ApplicationRecord + extend FriendlyId + friendly_id :name, use: :slugged + + has_one_attached :banner + has_one_attached :foreground + has_one_attached :background + has_one_attached :audio + has_one_attached :video + + has_many :sermon_authors, dependent: :destroy + has_many :authors, through: :sermon_authors + has_many :sermon_scriptures, dependent: :destroy + has_many :scriptures, through: :sermon_scriptures + has_many :sermon_series, dependent: :destroy + has_many :series, through: :sermon_series + has_many :sermon_topics, dependent: :destroy + has_many :topics, through: :sermon_topics + + accepts_nested_attributes_for :sermon_scriptures + + validates :name, presence: true + + scope :published, -> { where.not(published_at: nil) } + scope :featured, -> { where.not(featured_at: nil) } + + def self.batch_publish(ids) + where(id: ids).find_each { |r| r.update(published_at: Time.zone.now) } + end + + def self.batch_unpublish(ids) + where(id: ids).find_each { |r| r.update(published_at: nil) } + end + + # Only allow these associations to be searchable by Ransack (used in ActiveAdmin filters) + def self.ransackable_associations(_auth_object = nil) + %w[authors scriptures series topics sermon_authors sermon_scriptures sermon_series sermon_topics] + end + + def self.ransackable_attributes(_auth_object = nil) + %w[created_at featured_at id name published_at slug updated_at snippet content] + end +end diff --git a/app/models/resource/connection/author.rb b/app/models/sermon_author.rb similarity index 53% rename from app/models/resource/connection/author.rb rename to app/models/sermon_author.rb index 0a5bea1..52adc93 100644 --- a/app/models/resource/connection/author.rb +++ b/app/models/sermon_author.rb @@ -1,14 +1,14 @@ # frozen_string_literal: true -class Resource::Connection::Author < ApplicationRecord - belongs_to :resource +class SermonAuthor < ApplicationRecord + belongs_to :sermon belongs_to :author def self.ransackable_attributes(_auth_object = nil) - %w[author_id created_at id resource_id updated_at] + %w[author_id created_at id sermon_id updated_at] end def self.ransackable_associations(_auth_object = nil) - %w[author resource] + %w[author sermon] end end diff --git a/app/models/resource/connection/scripture.rb b/app/models/sermon_scripture.rb similarity index 75% rename from app/models/resource/connection/scripture.rb rename to app/models/sermon_scripture.rb index f9f8a1c..364dd77 100644 --- a/app/models/resource/connection/scripture.rb +++ b/app/models/sermon_scripture.rb @@ -1,17 +1,17 @@ # frozen_string_literal: true -class Resource::Connection::Scripture < ApplicationRecord - belongs_to :resource +class SermonScripture < ApplicationRecord + belongs_to :sermon belongs_to :scripture, class_name: '::Scripture' before_save :fetch_content, if: :range_changed? def self.ransackable_attributes(_auth_object = nil) - %w[content created_at id range resource_id scripture_id updated_at] + %w[content created_at id range sermon_id scripture_id updated_at] end def self.ransackable_associations(_auth_object = nil) - %w[resource scripture] + %w[sermon scripture] end protected diff --git a/app/models/sermon_series.rb b/app/models/sermon_series.rb new file mode 100644 index 0000000..5ff7288 --- /dev/null +++ b/app/models/sermon_series.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +class SermonSeries < ApplicationRecord + belongs_to :sermon + belongs_to :series + + def self.ransackable_attributes(_auth_object = nil) + %w[created_at id sermon_id series_id updated_at] + end + + def self.ransackable_associations(_auth_object = nil) + %w[sermon series] + end +end diff --git a/app/models/resource/connection/topic.rb b/app/models/sermon_topic.rb similarity index 57% rename from app/models/resource/connection/topic.rb rename to app/models/sermon_topic.rb index 0210d05..dbc246d 100644 --- a/app/models/resource/connection/topic.rb +++ b/app/models/sermon_topic.rb @@ -1,14 +1,14 @@ # frozen_string_literal: true -class Resource::Connection::Topic < ApplicationRecord - belongs_to :resource +class SermonTopic < ApplicationRecord + belongs_to :sermon belongs_to :topic, class_name: 'Category::Topic' def self.ransackable_attributes(_auth_object = nil) - %w[created_at id resource_id topic_id updated_at] + %w[created_at id sermon_id topic_id updated_at] end def self.ransackable_associations(_auth_object = nil) - %w[resource topic] + %w[sermon topic] end end diff --git a/app/models/step.rb b/app/models/step.rb deleted file mode 100644 index 648df84..0000000 --- a/app/models/step.rb +++ /dev/null @@ -1,28 +0,0 @@ -# frozen_string_literal: true - -class Step < ApplicationRecord - acts_as_list - has_many :location_connection_steps, dependent: :destroy, class_name: 'Location::Connection::Step' - has_one_attached :banner - validates :name, :content, presence: true - validates :banner, - attached: true, - aspect_ratio: :is_16_9, - content_type: %r{\Aimage/.*\z}, - dimension: { - width: { in: 0..1920 }, - height: { in: 0..1080 }, - message: '1920x1080 max resolution' - }, - size: { less_than: 500.kilobytes, message: '500KB max size' } - scope :featured, -> { where.not(featured_at: nil) } - - # No association filters in ActiveAdmin, so none are ransackable - def self.ransackable_associations(_auth_object = nil) - [] - end - - def self.ransackable_attributes(_auth_object = nil) - %w[content created_at featured_at id name position updated_at] - end -end diff --git a/app/services/import/wpfc_service.rb b/app/services/import/wpfc_service.rb index be8a777..43922f4 100644 --- a/app/services/import/wpfc_service.rb +++ b/app/services/import/wpfc_service.rb @@ -37,10 +37,10 @@ def import_authors def import_sermons items('wpfc_sermon').each do |remote_sermon| - sermon = Resource::Sermon.find_or_initialize_by(remote_id: remote_sermon['id']) + sermon = Sermon.find_or_initialize_by(remote_id: remote_sermon['id']) sermon.name = CGI.unescapeHTML(remote_sermon['title']['rendered']) sermon.slug = remote_sermon['slug'] - sermon.connection_scriptures = connection_scriptures(remote_sermon['bible_passage']) + sermon.sermon_scriptures = sermon_scriptures(remote_sermon['bible_passage']) sermon.authors = Author.where(remote_id: remote_sermon['wpfc_preacher']) sermon.series = Series.where(remote_id: remote_sermon['wpfc_sermon_series']) sermon.audio_url = remote_sermon['sermon_audio'] @@ -49,12 +49,12 @@ def import_sermons end end - def connection_scriptures(bible_passage) + def sermon_scriptures(bible_passage) matches = bible_passage.match(/(?[\dA-Za-z ]*) (?[\d:-]*)/) return [] if matches.blank? Scripture.where(name: matches[:name]).map do |scripture| - Resource::Connection::Scripture.new(scripture: scripture, range: matches[:range]) + SermonScripture.new(scripture: scripture, range: matches[:range]) end end diff --git a/app/views/application/_links.html.erb b/app/views/application/_links.html.erb index 648e0ca..ef47fec 100644 --- a/app/views/application/_links.html.erb +++ b/app/views/application/_links.html.erb @@ -1,16 +1,9 @@