rails_claude_skills 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (87) hide show
  1. checksums.yaml +7 -0
  2. data/.github/ISSUE_TEMPLATE/bug_report.yml +134 -0
  3. data/.github/ISSUE_TEMPLATE/config.yml +11 -0
  4. data/.github/ISSUE_TEMPLATE/feature_request.yml +129 -0
  5. data/.github/ISSUE_TEMPLATE/question.yml +90 -0
  6. data/.github/dependabot.yml +19 -0
  7. data/.github/workflows/ci.yml +77 -0
  8. data/.github/workflows/release.yml +66 -0
  9. data/.rubocop.yml +52 -0
  10. data/CHANGELOG.md +94 -0
  11. data/CLAUDE.md +332 -0
  12. data/CODE_OF_CONDUCT.md +134 -0
  13. data/CONTRIBUTING.md +580 -0
  14. data/LICENSE.txt +21 -0
  15. data/README.md +544 -0
  16. data/Rakefile +8 -0
  17. data/lib/generators/claude/agent/agent_generator.rb +71 -0
  18. data/lib/generators/claude/agent/templates/agent.md.tt +62 -0
  19. data/lib/generators/claude/command/command_generator.rb +50 -0
  20. data/lib/generators/claude/command/templates/command.md.tt +28 -0
  21. data/lib/generators/claude/commands_library/create-pr.md +27 -0
  22. data/lib/generators/claude/commands_library/dbchange.md +19 -0
  23. data/lib/generators/claude/commands_library/quality.md +20 -0
  24. data/lib/generators/claude/commands_library/stimulus.md +19 -0
  25. data/lib/generators/claude/commands_library/turbo-feature.md +17 -0
  26. data/lib/generators/claude/install/install_generator.rb +211 -0
  27. data/lib/generators/claude/install/templates/README.md.tt +59 -0
  28. data/lib/generators/claude/install/templates/USAGE +28 -0
  29. data/lib/generators/claude/install/templates/agents/api-dev.md.tt +46 -0
  30. data/lib/generators/claude/install/templates/agents/fullstack-dev.md.tt +48 -0
  31. data/lib/generators/claude/install/templates/agents/rails-developer.md.tt +40 -0
  32. data/lib/generators/claude/install/templates/settings.local.json.tt +13 -0
  33. data/lib/generators/claude/rule/rule_generator.rb +175 -0
  34. data/lib/generators/claude/rule/templates/rule.md.tt +7 -0
  35. data/lib/generators/claude/rules_library/code-style.md +37 -0
  36. data/lib/generators/claude/rules_library/database.md +47 -0
  37. data/lib/generators/claude/rules_library/hotwire.md +56 -0
  38. data/lib/generators/claude/rules_library/security.md +54 -0
  39. data/lib/generators/claude/rules_library/testing.md +47 -0
  40. data/lib/generators/claude/skill/skill_generator.rb +196 -0
  41. data/lib/generators/claude/skill/templates/SKILL.md.tt +27 -0
  42. data/lib/generators/claude/skills_library/create-task-files/SKILL.md +311 -0
  43. data/lib/generators/claude/skills_library/create-task-files/templates/bug.md +60 -0
  44. data/lib/generators/claude/skills_library/create-task-files/templates/epic.md +47 -0
  45. data/lib/generators/claude/skills_library/create-task-files/templates/issue.md +45 -0
  46. data/lib/generators/claude/skills_library/create-task-files/templates/user-story.md +57 -0
  47. data/lib/generators/claude/skills_library/minitest-testing/SKILL.md +398 -0
  48. data/lib/generators/claude/skills_library/minitest-testing/references/examples.md +889 -0
  49. data/lib/generators/claude/skills_library/plan-feature/SKILL.md +253 -0
  50. data/lib/generators/claude/skills_library/rails-api-controllers/SKILL.md +1041 -0
  51. data/lib/generators/claude/skills_library/rails-api-controllers/references/api-documentation.md +422 -0
  52. data/lib/generators/claude/skills_library/rails-api-controllers/references/serialization.md +456 -0
  53. data/lib/generators/claude/skills_library/rails-auth-with-devise/SKILL.md +191 -0
  54. data/lib/generators/claude/skills_library/rails-auth-with-devise/references/advanced.md +331 -0
  55. data/lib/generators/claude/skills_library/rails-auth-with-devise/references/api-auth.md +266 -0
  56. data/lib/generators/claude/skills_library/rails-auth-with-devise/references/omniauth.md +194 -0
  57. data/lib/generators/claude/skills_library/rails-authorization-cancancan/SKILL.md +603 -0
  58. data/lib/generators/claude/skills_library/rails-authorization-cancancan/references/api-authorization.md +543 -0
  59. data/lib/generators/claude/skills_library/rails-authorization-cancancan/references/complex-permissions.md +572 -0
  60. data/lib/generators/claude/skills_library/rails-authorization-cancancan/references/multi-tenancy.md +373 -0
  61. data/lib/generators/claude/skills_library/rails-controllers/SKILL.md +514 -0
  62. data/lib/generators/claude/skills_library/rails-debugging/SKILL.md +260 -0
  63. data/lib/generators/claude/skills_library/rails-deployment/SKILL.md +437 -0
  64. data/lib/generators/claude/skills_library/rails-deployment/references/examples.md +901 -0
  65. data/lib/generators/claude/skills_library/rails-hotwire/SKILL.md +367 -0
  66. data/lib/generators/claude/skills_library/rails-jobs/MISSION_CONTROL_SETUP.md +639 -0
  67. data/lib/generators/claude/skills_library/rails-jobs/SKILL.md +704 -0
  68. data/lib/generators/claude/skills_library/rails-mailers/SKILL.md +549 -0
  69. data/lib/generators/claude/skills_library/rails-models/SKILL.md +379 -0
  70. data/lib/generators/claude/skills_library/rails-pagination-kaminari/SKILL.md +622 -0
  71. data/lib/generators/claude/skills_library/rails-pagination-kaminari/references/api-pagination.md +523 -0
  72. data/lib/generators/claude/skills_library/rails-pagination-kaminari/references/custom-themes.md +498 -0
  73. data/lib/generators/claude/skills_library/rails-pagination-kaminari/references/performance.md +478 -0
  74. data/lib/generators/claude/skills_library/rails-views/SKILL.md +508 -0
  75. data/lib/generators/claude/skills_library/refine-requirements/SKILL.md +226 -0
  76. data/lib/generators/claude/skills_library/refine-requirements/references/examples.md +344 -0
  77. data/lib/generators/claude/skills_library/refine-requirements/references/reference.md +298 -0
  78. data/lib/generators/claude/skills_library/rspec-testing/SKILL.md +572 -0
  79. data/lib/generators/claude/skills_library/rspec-testing/references/better_specs_guide.md +273 -0
  80. data/lib/generators/claude/skills_library/rspec-testing/references/thoughtbot_patterns.md +407 -0
  81. data/lib/generators/claude/skills_library/tailwindcss/SKILL.md +371 -0
  82. data/lib/generators/claude/views/views_generator.rb +113 -0
  83. data/lib/rails_claude_skills/railtie.rb +16 -0
  84. data/lib/rails_claude_skills/version.rb +5 -0
  85. data/lib/rails_claude_skills.rb +27 -0
  86. data/sig/rails_claude_skills.rbs +4 -0
  87. metadata +199 -0
@@ -0,0 +1,456 @@
1
+ # JSON Serialization Patterns
2
+
3
+ Control how your models are serialized to JSON for API responses. Choose the right serialization approach based on your needs.
4
+
5
+ ## Default Rails Serialization
6
+
7
+ Rails provides basic JSON serialization out of the box:
8
+
9
+ ### as_json / to_json
10
+
11
+ ```ruby
12
+ # In controller
13
+ def show
14
+ render json: @article
15
+ end
16
+
17
+ # Customize in model
18
+ class Article < ApplicationRecord
19
+ def as_json(options = {})
20
+ super(
21
+ only: [:id, :title, :body, :status],
22
+ include: {
23
+ author: { only: [:id, :name, :email] },
24
+ comments: { only: [:id, :body, :created_at] }
25
+ },
26
+ methods: [:word_count]
27
+ )
28
+ end
29
+
30
+ def word_count
31
+ body.split.size
32
+ end
33
+ end
34
+ ```
35
+
36
+ **Pros:** Built-in, no dependencies
37
+ **Cons:** Mixes presentation logic with models, not reusable
38
+
39
+ ## Jbuilder (Rails Default)
40
+
41
+ Jbuilder uses view templates for JSON responses:
42
+
43
+ ### Basic Usage
44
+
45
+ ```ruby
46
+ # app/views/api/v1/articles/show.json.jbuilder
47
+ json.article do
48
+ json.id @article.id
49
+ json.title @article.title
50
+ json.body @article.body
51
+ json.status @article.status
52
+ json.created_at @article.created_at
53
+
54
+ json.author do
55
+ json.id @article.author.id
56
+ json.name @article.author.name
57
+ json.email @article.author.email
58
+ end
59
+ end
60
+ ```
61
+
62
+ ### Collections
63
+
64
+ ```ruby
65
+ # app/views/api/v1/articles/index.json.jbuilder
66
+ json.data @articles do |article|
67
+ json.id article.id
68
+ json.title article.title
69
+ json.excerpt article.body.truncate(100)
70
+ json.author_name article.author.name
71
+ end
72
+
73
+ json.meta do
74
+ json.current_page @articles.current_page
75
+ json.total_pages @articles.total_pages
76
+ json.total_count @articles.total_count
77
+ end
78
+ ```
79
+
80
+ ### Partials
81
+
82
+ ```ruby
83
+ # app/views/api/v1/articles/_article.json.jbuilder
84
+ json.extract! article, :id, :title, :body, :status, :created_at
85
+
86
+ json.author do
87
+ json.partial! 'api/v1/users/user', user: article.author
88
+ end
89
+
90
+ # app/views/api/v1/articles/show.json.jbuilder
91
+ json.article do
92
+ json.partial! 'article', article: @article
93
+ end
94
+ ```
95
+
96
+ **Pros:** Familiar view-based approach, good for complex nested data
97
+ **Cons:** Slower than other options, requires view files
98
+
99
+ ## ActiveModelSerializers (AMS)
100
+
101
+ Class-based serializers with conventions:
102
+
103
+ ### Installation
104
+
105
+ ```ruby
106
+ # Gemfile
107
+ gem 'active_model_serializers', '~> 0.10.0'
108
+ ```
109
+
110
+ ### Basic Serializer
111
+
112
+ ```ruby
113
+ # app/serializers/article_serializer.rb
114
+ class ArticleSerializer < ActiveModel::Serializer
115
+ attributes :id, :title, :body, :status, :created_at, :word_count
116
+
117
+ belongs_to :author
118
+ has_many :comments
119
+
120
+ def word_count
121
+ object.body.split.size
122
+ end
123
+ end
124
+
125
+ # app/serializers/author_serializer.rb
126
+ class AuthorSerializer < ActiveModel::Serializer
127
+ attributes :id, :name, :email
128
+ end
129
+
130
+ # Controller automatically uses serializer
131
+ def show
132
+ render json: @article # Uses ArticleSerializer
133
+ end
134
+ ```
135
+
136
+ ### Conditional Attributes
137
+
138
+ ```ruby
139
+ class ArticleSerializer < ActiveModel::Serializer
140
+ attributes :id, :title, :body, :draft_notes
141
+
142
+ def draft_notes
143
+ object.draft_notes if object.status == 'draft'
144
+ end
145
+
146
+ def include_draft_notes?
147
+ object.status == 'draft'
148
+ end
149
+ end
150
+ ```
151
+
152
+ ### Custom Serializers
153
+
154
+ ```ruby
155
+ # Use specific serializer
156
+ render json: @article, serializer: ArticleDetailSerializer
157
+
158
+ # Disable serializer
159
+ render json: @article, serializer: nil
160
+
161
+ # Collection with meta
162
+ render json: @articles,
163
+ meta: { total_count: @articles.total_count },
164
+ meta_key: 'pagination'
165
+ ```
166
+
167
+ **Pros:** Convention over configuration, automatic associations
168
+ **Cons:** Slower than simpler alternatives, less active maintenance
169
+
170
+ ## Blueprinter (Recommended)
171
+
172
+ Fast, declarative serialization with great performance:
173
+
174
+ ### Installation
175
+
176
+ ```ruby
177
+ # Gemfile
178
+ gem 'blueprinter'
179
+ ```
180
+
181
+ ### Basic Blueprint
182
+
183
+ ```ruby
184
+ # app/blueprints/article_blueprint.rb
185
+ class ArticleBlueprint < Blueprinter::Base
186
+ identifier :id
187
+
188
+ fields :title, :body, :status, :created_at
189
+
190
+ field :word_count do |article|
191
+ article.body.split.size
192
+ end
193
+
194
+ association :author, blueprint: AuthorBlueprint
195
+ association :comments, blueprint: CommentBlueprint
196
+ end
197
+
198
+ # app/blueprints/author_blueprint.rb
199
+ class AuthorBlueprint < Blueprinter::Base
200
+ identifier :id
201
+ fields :name, :email
202
+ end
203
+
204
+ # In controller
205
+ def show
206
+ render json: ArticleBlueprint.render(@article)
207
+ end
208
+
209
+ def index
210
+ render json: ArticleBlueprint.render(@articles)
211
+ end
212
+ ```
213
+
214
+ ### Views (Different Representations)
215
+
216
+ ```ruby
217
+ class ArticleBlueprint < Blueprinter::Base
218
+ identifier :id
219
+
220
+ # Default view
221
+ fields :title, :status, :created_at
222
+
223
+ # Extended view with more fields
224
+ view :extended do
225
+ fields :body, :updated_at
226
+ association :author, blueprint: AuthorBlueprint
227
+ end
228
+
229
+ # Summary view with minimal fields
230
+ view :summary do
231
+ field :title
232
+ field :excerpt do |article|
233
+ article.body.truncate(100)
234
+ end
235
+ end
236
+ end
237
+
238
+ # Usage
239
+ ArticleBlueprint.render(@article) # Default view
240
+ ArticleBlueprint.render(@article, view: :extended) # Extended view
241
+ ArticleBlueprint.render(@articles, view: :summary) # Summary for list
242
+ ```
243
+
244
+ ### Conditional Fields
245
+
246
+ ```ruby
247
+ class ArticleBlueprint < Blueprinter::Base
248
+ fields :id, :title, :body
249
+
250
+ field :draft_notes, if: ->(article, _options) { article.status == 'draft' }
251
+
252
+ field :edit_url, if: ->(article, options) {
253
+ options[:current_user]&.can_edit?(article)
254
+ }
255
+ end
256
+
257
+ # Usage
258
+ ArticleBlueprint.render(@article, current_user: current_user)
259
+ ```
260
+
261
+ ### Meta and Root
262
+
263
+ ```ruby
264
+ # With meta
265
+ render json: ArticleBlueprint.render(@articles, meta: {
266
+ total_count: @articles.total_count,
267
+ current_page: @articles.current_page
268
+ })
269
+
270
+ # Output:
271
+ # {
272
+ # "data": [...articles...],
273
+ # "meta": { "total_count": 42, "current_page": 1 }
274
+ # }
275
+
276
+ # Custom root
277
+ ArticleBlueprint.render(@articles, root: :articles)
278
+ # { "articles": [...] }
279
+ ```
280
+
281
+ **Pros:** Fast (5-10x faster than AMS), simple, flexible views
282
+ **Cons:** Less magic, more explicit
283
+
284
+ ## JSONAPI::Serializer (formerly fast_jsonapi)
285
+
286
+ JSON:API specification compliant serialization:
287
+
288
+ ### Installation
289
+
290
+ ```ruby
291
+ # Gemfile
292
+ gem 'jsonapi-serializer'
293
+ ```
294
+
295
+ ### Basic Serializer
296
+
297
+ ```ruby
298
+ # app/serializers/article_serializer.rb
299
+ class ArticleSerializer
300
+ include JSONAPI::Serializer
301
+
302
+ attributes :title, :body, :status, :created_at
303
+
304
+ attribute :word_count do |article|
305
+ article.body.split.size
306
+ end
307
+
308
+ belongs_to :author
309
+ has_many :comments
310
+ end
311
+
312
+ # In controller
313
+ def show
314
+ render json: ArticleSerializer.new(@article).serializable_hash
315
+ end
316
+ ```
317
+
318
+ ### JSON:API Response Format
319
+
320
+ ```json
321
+ {
322
+ "data": {
323
+ "id": "1",
324
+ "type": "article",
325
+ "attributes": {
326
+ "title": "Rails API Guide",
327
+ "body": "Content here...",
328
+ "status": "published",
329
+ "created_at": "2025-01-15T10:00:00Z"
330
+ },
331
+ "relationships": {
332
+ "author": {
333
+ "data": { "id": "5", "type": "user" }
334
+ }
335
+ }
336
+ },
337
+ "included": [
338
+ {
339
+ "id": "5",
340
+ "type": "user",
341
+ "attributes": {
342
+ "name": "John Doe"
343
+ }
344
+ }
345
+ ]
346
+ }
347
+ ```
348
+
349
+ ### With Includes
350
+
351
+ ```ruby
352
+ # Include related resources
353
+ options = { include: [:author, :comments] }
354
+ ArticleSerializer.new(@article, options).serializable_hash
355
+
356
+ # Conditional includes based on params
357
+ def show
358
+ options = {}
359
+ options[:include] = params[:include].split(',') if params[:include].present?
360
+
361
+ render json: ArticleSerializer.new(@article, options).serializable_hash
362
+ end
363
+ ```
364
+
365
+ **Pros:** JSON:API compliant, fast, handles includes well
366
+ **Cons:** Opinionated format, more verbose responses
367
+
368
+ ## Comparison Table
369
+
370
+ | Gem | Speed | Flexibility | Learning Curve | Use Case |
371
+ |-----|-------|-------------|----------------|----------|
372
+ | **as_json** | Fast | Low | Easy | Simple APIs, prototypes |
373
+ | **Jbuilder** | Slow | High | Easy | Complex nested data, familiar views |
374
+ | **AMS** | Slow | Medium | Medium | Rails conventions, associations |
375
+ | **Blueprinter** | Very Fast | High | Easy | Production APIs, performance-critical |
376
+ | **JSONAPI::Serializer** | Fast | Medium | Medium | JSON:API clients, standardized APIs |
377
+
378
+ ## Recommendation by Project Size
379
+
380
+ ### Small Projects / Prototypes
381
+ Use Rails default `as_json` or Jbuilder:
382
+ ```ruby
383
+ render json: @article.as_json(only: [:id, :title], include: :author)
384
+ ```
385
+
386
+ ### Medium Projects
387
+ Use Blueprinter for simplicity and speed:
388
+ ```ruby
389
+ ArticleBlueprint.render(@article, view: :detailed)
390
+ ```
391
+
392
+ ### Large Projects / JSON:API Clients
393
+ Use JSONAPI::Serializer for spec compliance:
394
+ ```ruby
395
+ ArticleSerializer.new(@article, include: [:author]).serializable_hash
396
+ ```
397
+
398
+ ## Performance Tips
399
+
400
+ 1. **Select Only Needed Fields**
401
+ ```ruby
402
+ # Bad - loads all columns
403
+ @articles = Article.all
404
+
405
+ # Good - only loads needed columns
406
+ @articles = Article.select(:id, :title, :body, :created_at)
407
+ ```
408
+
409
+ 2. **Eager Load Associations**
410
+ ```ruby
411
+ # Bad - N+1 queries
412
+ @articles = Article.all
413
+
414
+ # Good - single query
415
+ @articles = Article.includes(:author, :comments)
416
+ ```
417
+
418
+ 3. **Use Caching**
419
+ ```ruby
420
+ # In serializer/blueprint
421
+ def show
422
+ json = Rails.cache.fetch([@article, 'v1']) do
423
+ ArticleBlueprint.render(@article)
424
+ end
425
+ render json: json
426
+ end
427
+ ```
428
+
429
+ 4. **Paginate Collections**
430
+ ```ruby
431
+ @articles = Article.page(params[:page]).per(20)
432
+ ```
433
+
434
+ ## Testing Serializers
435
+
436
+ ```ruby
437
+ # spec/blueprints/article_blueprint_spec.rb
438
+ RSpec.describe ArticleBlueprint do
439
+ let(:article) { create(:article, title: 'Test') }
440
+
441
+ it 'serializes basic fields' do
442
+ result = JSON.parse(ArticleBlueprint.render(article))
443
+
444
+ expect(result['id']).to eq(article.id)
445
+ expect(result['title']).to eq('Test')
446
+ expect(result).to have_key('created_at')
447
+ end
448
+
449
+ it 'includes author in extended view' do
450
+ result = JSON.parse(ArticleBlueprint.render(article, view: :extended))
451
+
452
+ expect(result).to have_key('author')
453
+ expect(result['author']['name']).to eq(article.author.name)
454
+ end
455
+ end
456
+ ```
@@ -0,0 +1,191 @@
1
+ ---
2
+ name: rails-auth-with-devise
3
+ description: "Complete authentication setup for Ruby on Rails applications using Devise. Use when: (1) Setting up user authentication in a Rails app, (2) Adding sign in/sign up/sign out functionality, (3) Implementing email confirmation, password recovery, or account locking, (4) Configuring OmniAuth social login, (5) Adding multiple user models (User/Admin), (6) Customizing Devise views or controllers, (7) Testing authentication with RSpec/Minitest, (8) API authentication setup"
4
+ ---
5
+
6
+ # Rails Authentication with Devise
7
+
8
+ Devise is the most popular authentication solution for Rails, providing a complete MVC solution with 10 modular components.
9
+
10
+ ## Quick Setup
11
+
12
+ ```bash
13
+ # Add to Gemfile
14
+ bundle add devise
15
+
16
+ # Install Devise
17
+ rails generate devise:install
18
+
19
+ # Generate User model with authentication
20
+ rails generate devise User
21
+
22
+ # Run migrations
23
+ rails db:migrate
24
+ ```
25
+
26
+ ## Essential Configuration
27
+
28
+ After `devise:install`, configure in `config/environments/development.rb`:
29
+ ```ruby
30
+ config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }
31
+ ```
32
+
33
+ Set root route in `config/routes.rb`:
34
+ ```ruby
35
+ root to: 'home#index'
36
+ ```
37
+
38
+ ## Devise Modules Reference
39
+
40
+ Enable modules in the model (e.g., `app/models/user.rb`):
41
+
42
+ | Module | Purpose | Migration Columns |
43
+ |--------|---------|-------------------|
44
+ | `:database_authenticatable` | Password hashing/storage | `email`, `encrypted_password` |
45
+ | `:registerable` | Sign up, edit, destroy account | - |
46
+ | `:recoverable` | Password reset via email | `reset_password_token`, `reset_password_sent_at` |
47
+ | `:rememberable` | "Remember me" cookie | `remember_created_at` |
48
+ | `:trackable` | Sign in stats | `sign_in_count`, `current_sign_in_at`, `last_sign_in_at`, `current_sign_in_ip`, `last_sign_in_ip` |
49
+ | `:validatable` | Email/password validations | - |
50
+ | `:confirmable` | Email confirmation | `confirmation_token`, `confirmed_at`, `confirmation_sent_at`, `unconfirmed_email` |
51
+ | `:lockable` | Lock after failed attempts | `failed_attempts`, `unlock_token`, `locked_at` |
52
+ | `:timeoutable` | Session expiration | - |
53
+ | `:omniauthable` | OAuth provider support | - |
54
+
55
+ ## Controller Helpers
56
+
57
+ ```ruby
58
+ # Require authentication
59
+ before_action :authenticate_user!
60
+
61
+ # Check if signed in
62
+ user_signed_in?
63
+
64
+ # Get current user
65
+ current_user
66
+
67
+ # Access session
68
+ user_session
69
+ ```
70
+
71
+ For other models (e.g., Admin):
72
+ ```ruby
73
+ before_action :authenticate_admin!
74
+ admin_signed_in?
75
+ current_admin
76
+ admin_session
77
+ ```
78
+
79
+ ## Common Tasks
80
+
81
+ ### Add Custom Fields (e.g., username)
82
+
83
+ 1. Generate migration:
84
+ ```bash
85
+ rails g migration AddUsernameToUsers username:string:uniq
86
+ rails db:migrate
87
+ ```
88
+
89
+ 2. Permit in `ApplicationController`:
90
+ ```ruby
91
+ class ApplicationController < ActionController::Base
92
+ before_action :configure_permitted_parameters, if: :devise_controller?
93
+
94
+ protected
95
+
96
+ def configure_permitted_parameters
97
+ devise_parameter_sanitizer.permit(:sign_up, keys: [:username])
98
+ devise_parameter_sanitizer.permit(:account_update, keys: [:username])
99
+ end
100
+ end
101
+ ```
102
+
103
+ ### Customize Views
104
+
105
+ ```bash
106
+ # Generate all views
107
+ rails generate devise:views
108
+
109
+ # Scoped views for specific model
110
+ rails generate devise:views users
111
+
112
+ # Specific modules only
113
+ rails generate devise:views -v registrations confirmations
114
+ ```
115
+
116
+ ### Customize Controllers
117
+
118
+ ```bash
119
+ # Generate controllers
120
+ rails generate devise:controllers users
121
+
122
+ # Or specific controller
123
+ rails generate devise:controllers users -c sessions registrations
124
+ ```
125
+
126
+ Update routes:
127
+ ```ruby
128
+ devise_for :users, controllers: {
129
+ sessions: 'users/sessions',
130
+ registrations: 'users/registrations'
131
+ }
132
+ ```
133
+
134
+ ### Custom Redirect After Sign In
135
+
136
+ In `ApplicationController`:
137
+ ```ruby
138
+ def after_sign_in_path_for(resource)
139
+ stored_location_for(resource) || dashboard_path
140
+ end
141
+
142
+ def after_sign_out_path_for(resource_or_scope)
143
+ root_path
144
+ end
145
+ ```
146
+
147
+ ## Hotwire/Turbo Configuration (Rails 7+)
148
+
149
+ In `config/initializers/devise.rb`:
150
+ ```ruby
151
+ Devise.setup do |config|
152
+ config.responder.error_status = :unprocessable_entity
153
+ config.responder.redirect_status = :see_other
154
+ end
155
+ ```
156
+
157
+ Ensure `responders` gem version >= 3.1.0.
158
+
159
+ ## Testing
160
+
161
+ ### RSpec Setup
162
+
163
+ In `spec/support/devise.rb`:
164
+ ```ruby
165
+ RSpec.configure do |config|
166
+ config.include Devise::Test::ControllerHelpers, type: :controller
167
+ config.include Devise::Test::ControllerHelpers, type: :view
168
+ config.include Devise::Test::IntegrationHelpers, type: :feature
169
+ config.include Devise::Test::IntegrationHelpers, type: :request
170
+ end
171
+ ```
172
+
173
+ Usage:
174
+ ```ruby
175
+ sign_in user
176
+ sign_out user
177
+ ```
178
+
179
+ ### Minitest Setup
180
+
181
+ ```ruby
182
+ class ActionDispatch::IntegrationTest
183
+ include Devise::Test::IntegrationHelpers
184
+ end
185
+ ```
186
+
187
+ ## Additional Guides
188
+
189
+ - **OmniAuth setup**: See [references/omniauth.md](references/omniauth.md)
190
+ - **API authentication**: See [references/api-auth.md](references/api-auth.md)
191
+ - **Advanced patterns**: See [references/advanced.md](references/advanced.md)