This file provides guidance to AI agents when working with code in this repository.
A Rails 8+ engine providing CRUD scaffolding. Consumer apps declare a Layered::Resource::Base subclass in app/layered_resources/ and a layered_resources :name route. README is the user-facing API reference.
bundle exec rake test # full suite
bundle exec rake test TEST=test/integration/layered_resource_crud_test.rb
cd test/dummy && bin/dev # manual explorationThree load-bearing pieces:
-
Layered::Resource::Base(lib/layered/resource/base.rb) - DSL (model,columns,fields,search_fields,default_sort,per_page) plus override points (scope,build_record,after_save_path).inherited_attributewalks the ancestor chain manually because class ivars aren't Ruby-inherited - this enables resource subclassing.configure_ransackpatchesransackable_attributes/ransackable_associationson the model but only responds when called with the resource class asauth_object; other callers fall through to the original methods, preserving host-app config. -
Layered::Resource::Routing(lib/layered/resource/routing.rb) - thelayered_resourcesroute DSL plus a process-wideConcurrent::Mapregistry. Each route bakes a_layered_resource_route_keydefault intopath_parametersso the controller can look up the right resource. Parses surroundingscopepaths at registration time for nested-route support. Raises early on incoherentonly:combos (e.g.:newwithout:create) - keep those guards in sync if adding actions. -
Layered::Resource::ResourcesController(app/controllers/layered/resource/resources_controller.rb) - inherits from the host app'sApplicationController, so itsbefore_actions (e.g. Devise) apply automatically.load_layered_resourcereads the route key, looks up the resource, and sets the@can_*action flags._prefixesis overridden soapp/views/layered/<name>/overrides win - this is what makesrails g layered:resource:viewsejection work.
Engine (lib/layered/resource/engine.rb) autoloads app/layered_resources, mixes Routing into Mapper, includes Pagy::Method, and prepends the engine view path.
- Tests in
test/integration/run againsttest/dummy/(a real Rails app withPostandUsermodels, plusPostResourceandUserResource). Integration tests are the contract for controller/routing/DSL changes. attribute_required?treats a field as required only when the presence validator is unconditional - don't tighten without considering conditional-validation forms.concurrent-rubyis depended on solely for the routing registry'sConcurrent::Map.
- Titles: capitalise first word only (e.g. "This title")
- Document new DSL surface in three places: the README (user-facing API reference), an integration test under
test/integration/exercising it against the dummy app, and.claude/skills/layered-resource-rails/SKILL.md. When a new DSL option needs a runnable example, wire it into the dummy app to show it working.