From 8d3d29c8a7f4da7281cc7e43a7298a385ab99bd9 Mon Sep 17 00:00:00 2001 From: DualFroz Date: Wed, 2 Sep 2026 19:40:21 +0200 Subject: [PATCH] feat(blog): extend app --- examples/blog/app.rb | 66 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 65 insertions(+), 1 deletion(-) diff --git a/examples/blog/app.rb b/examples/blog/app.rb index 98ae225..da94706 100644 --- a/examples/blog/app.rb +++ b/examples/blog/app.rb @@ -162,5 +162,69 @@ class Blog < Prism::Application websocket '/cable', PostActivityChannel, max_message_size: 2048 root(to: 'posts#index') - resources :posts, only: %i[index show create] + resource :session, only: %i[new create destroy] + # Not a `resource`/`resources` - the record this is "about" is only ever + # addressed by a signed token in the URL, never by a User id (that would + # let anyone reset any account by guessing/incrementing ids), so it has + # no numeric-id member routes to fall out of that DSL. + get('/password_resets/new', to: 'password_resets#new', as: :new_password_reset) + post('/password_resets', to: 'password_resets#create', as: :password_resets) + get('/password_resets/:token/edit', to: 'password_resets#edit', as: :edit_password_reset) + patch('/password_resets/:token', to: 'password_resets#update', as: :password_reset) + # Same reasoning as password_resets above - addressed only by a signed + # token, never by User id. + get('/email_confirmations/new', to: 'email_confirmations#new', as: :new_email_confirmation) + post('/email_confirmations', to: 'email_confirmations#create', as: :email_confirmations) + get('/email_confirmations/:token', to: 'email_confirmations#show', as: :email_confirmation) + resource :account, only: %i[edit update] + # Flat, not nested under a post - a user's own comment history spans every + # post they ever commented on, same shape as GET /comments/trash below but + # for live (not soft-deleted) comments. See AccountController#comments. + get('/account/comments', to: 'account#comments', as: :account_comments) + # Flat, same reasoning as /account/comments above but filtered to + # pending instead of to authorship - see AccountController#moderation. + get('/account/moderation', to: 'account#moderation', as: :account_moderation) + resources :users, only: %i[new create] + # param: :slug - post URLs are /posts/some-title, not /posts/42 (see + # Post#to_param and Post.create_with_unique_slug). Nested comment routes + # stay /posts/:post_id/... (ResourceScope#nested_prefix hardcodes the + # segment name to "#{singular}_id" regardless of the parent's own param - + # only the VALUE passed for that segment becomes a slug string instead of + # a numeric id, see CommentsController). + resources :posts, only: %i[index show create edit update destroy], param: :slug do + collection do + get(:trash) + get(:export) + post(:import) + end + member do + patch(:preview) + patch(:publish) + patch(:unpublish) + patch(:restore) + patch(:move_up) + patch(:move_down) + end + resources :comments, only: %i[index create edit update destroy] do + member do + patch(:approve) + patch(:reject) + end + end + # create-only - see ClaimsController, a claim has no update/destroy + # anywhere in this app. + resources :claims, only: %i[create] + end + # Flat, not nested under a post - a commenter's own trashed comments span + # every post they ever wrote on, and restoring one is independent of + # whatever trash/restore state its post happens to be in (see + # CommentsController#trash/#restore). + get('/comments/trash', to: 'comments#trash', as: :trash_comments) + patch('/comments/:id/restore', to: 'comments#restore', as: :restore_comment) + resources :likes, only: %i[create destroy] + resources :login_sessions, only: %i[index destroy] do + collection do + post(:sign_out_others) + end + end end