1 Commits

Author SHA1 Message Date
Rockwell Windsor Rice
c5cec96c58
feat: add Rails 8 application CLAUDE.md example (#2258)
* feat: add Rails 8 application CLAUDE.md example

Adds examples/rails-app-CLAUDE.md as a reference template for Rails 8 applications.

- Add examples/rails-app-CLAUDE.md: full-stack Rails 8 template covering Hotwire (Turbo + Stimulus), ViewComponent, the Solid stack (SolidQueue, SolidCache, SolidCable), service objects, query objects, and Pundit authorization
- Aligns with existing rules/ruby/ conventions (Rails Way first, SolidQueue for greenfield, Hotwire-preferred, Rails 8 generated authentication)
- Includes five Key Patterns code blocks: service object, skinny controller, query object, background job, RSpec test

	new file:   examples/rails-app-CLAUDE.md

* fix(examples): correct Rails 8 CLAUDE.md examples for auth, transactions, and terminology

- Remove Django `select_related` terminology in favor of direct Rails methods
- Replace `authenticate_user!` (Devise-only) with `require_authentication` (Rails 8 generator default), with inline comment noting Devise as the alternative
- Move `send_notifications` outside the transaction block in the service object example so it only runs after a confirmed commit; safe with both SolidQueue and Sidekiq
- Remove `puts` from the N+1 BAD/GOOD example to align with the Ruby Conventions rule that bans `puts` in committed code

* fix(examples): improve idempotency, notification handling, and job argument guidance

- Wrap send_notifications in its own rescue block so notification failures are logged but do not raise out of the service object, preserving the Result-based error handling pattern
- Update the background job example to show an idempotency_key passed to the external API call, so the example is retry-safe by default rather than relying on a comment to flag the limitation
- Add a Background Jobs rule about pairing local idempotency checks with API-level idempotency tokens and considering with_lock for high-concurrency scenarios
- Soften the absolute "never records" claim for job arguments to explain the real reason (ActiveJob::DeserializationError when records are deleted between enqueue and execute)

* fix(examples): use exported_at.present? to match the column the example writes

The previous `exported?` check assumed a predicate method on the model that this example does not define. Using `exported_at.present?` keeps the guard consistent with the column the next line writes to in `update!(exported_at: Time.current)`.
2026-06-15 14:01:43 -04:00