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,549 @@
1
+ ---
2
+ name: rails-mailers
3
+ description: Use when sending emails - ActionMailer with async delivery via SolidQueue, templates, previews, and testing
4
+ ---
5
+
6
+ # Email with ActionMailer
7
+
8
+ Send transactional and notification emails using ActionMailer, integrated with SolidQueue for async delivery. Create HTML and text templates, preview emails in development, and test thoroughly.
9
+
10
+ <when-to-use>
11
+ - Sending transactional emails (password resets, confirmations, receipts)
12
+ - Sending notification emails (updates, alerts, digests)
13
+ - Delivering emails asynchronously via background jobs
14
+ - Creating email templates with HTML and text versions
15
+ - Testing email delivery and content
16
+ </when-to-use>
17
+
18
+ <benefits>
19
+ - **Async Delivery** - ActionMailer integrates with SolidQueue for non-blocking email sending
20
+ - **Template Support** - ERB templates for HTML and text email versions
21
+ - **Preview in Development** - See emails without sending via /rails/mailers
22
+ - **Testing Support** - Full test suite for delivery and content
23
+ - **Layouts** - Shared layouts for consistent email branding
24
+ - **Attachments** - Send files (PDFs, images) with emails
25
+ </benefits>
26
+
27
+ <verification-checklist>
28
+ Before completing mailer work:
29
+ - ✅ Async delivery used (deliver_later, not deliver_now)
30
+ - ✅ Both HTML and text templates provided
31
+ - ✅ URL helpers used (not path helpers)
32
+ - ✅ Email previews created for development
33
+ - ✅ Mailer tests passing (delivery and content)
34
+ - ✅ SolidQueue configured for background delivery
35
+ </verification-checklist>
36
+
37
+ <standards>
38
+ - ALWAYS deliver emails asynchronously with deliver_later (NOT deliver_now)
39
+ - Provide both HTML and text email templates
40
+ - Use *_url helpers (NOT *_path) for links in emails
41
+ - Set default 'from' address in ApplicationMailer
42
+ - Create email previews for development (/rails/mailers)
43
+ - Configure default_url_options for each environment
44
+ - Use inline CSS for email styling (email clients strip external styles)
45
+ - Test email delivery and content
46
+ - Use parameterized mailers (.with()) for cleaner syntax
47
+ </standards>
48
+
49
+ ---
50
+
51
+ ## ActionMailer Setup
52
+
53
+ <pattern name="actionmailer-basic-setup">
54
+ <description>Configure ActionMailer for email delivery</description>
55
+
56
+ **Mailer Class:**
57
+
58
+ ```ruby
59
+ # app/mailers/application_mailer.rb
60
+ class ApplicationMailer < ActionMailer::Base
61
+ default from: "noreply@example.com"
62
+ layout "mailer"
63
+ end
64
+
65
+ # app/mailers/notification_mailer.rb
66
+ class NotificationMailer < ApplicationMailer
67
+ def welcome_email(user)
68
+ @user = user
69
+ @login_url = login_url
70
+ mail(to: user.email, subject: "Welcome to Our App")
71
+ end
72
+
73
+ def password_reset(user)
74
+ @user = user
75
+ @reset_url = password_reset_url(user.reset_token)
76
+ mail(to: user.email, subject: "Password Reset Instructions")
77
+ end
78
+ end
79
+ ```
80
+
81
+ **HTML Template:**
82
+
83
+ ```erb
84
+ <%# app/views/notification_mailer/welcome_email.html.erb %>
85
+ <h1>Welcome, <%= @user.name %>!</h1>
86
+ <p>Thanks for signing up. Get started by logging in:</p>
87
+ <%= link_to "Login Now", @login_url, class: "button" %>
88
+ ```
89
+
90
+ **Text Template:**
91
+
92
+ ```erb
93
+ <%# app/views/notification_mailer/welcome_email.text.erb %>
94
+ Welcome, <%= @user.name %>!
95
+
96
+ Thanks for signing up. Get started by logging in:
97
+ <%= @login_url %>
98
+ ```
99
+
100
+ **Usage (Async with SolidQueue):**
101
+
102
+ ```ruby
103
+ # In controller or service
104
+ NotificationMailer.welcome_email(@user).deliver_later
105
+ NotificationMailer.password_reset(@user).deliver_later(queue: :mailers)
106
+ ```
107
+
108
+ **Why:** ActionMailer integrates seamlessly with SolidQueue for async delivery. Always use deliver_later to avoid blocking requests. Provide both HTML and text versions for compatibility.
109
+ </pattern>
110
+
111
+ <antipattern>
112
+ <description>Using deliver_now in production (blocks HTTP request)</description>
113
+ <bad-example>
114
+
115
+ ```ruby
116
+ # ❌ WRONG - Blocks HTTP request thread
117
+ def create
118
+ @user = User.create!(user_params)
119
+ NotificationMailer.welcome_email(@user).deliver_now # Blocks!
120
+ redirect_to @user
121
+ end
122
+ ```
123
+
124
+ </bad-example>
125
+ <good-example>
126
+
127
+ ```ruby
128
+ # ✅ CORRECT - Async delivery via SolidQueue
129
+ def create
130
+ @user = User.create!(user_params)
131
+ NotificationMailer.welcome_email(@user).deliver_later # Non-blocking
132
+ redirect_to @user
133
+ end
134
+ ```
135
+
136
+ </good-example>
137
+
138
+ **Why bad:** deliver_now blocks the HTTP request until SMTP completes, creating slow response times and poor user experience. deliver_later uses SolidQueue to send email in background.
139
+ </antipattern>
140
+
141
+ <pattern name="parameterized-mailers">
142
+ <description>Use .with() to pass parameters cleanly to mailers</description>
143
+
144
+ ```ruby
145
+ class NotificationMailer < ApplicationMailer
146
+ def custom_notification
147
+ @user = params[:user]
148
+ @message = params[:message]
149
+ mail(to: @user.email, subject: params[:subject])
150
+ end
151
+ end
152
+
153
+ # Usage
154
+ NotificationMailer.with(
155
+ user: user,
156
+ message: "Update available",
157
+ subject: "System Alert"
158
+ ).custom_notification.deliver_later
159
+ ```
160
+
161
+ **Why:** Cleaner syntax, easier to read and modify, and works seamlessly with background jobs.
162
+ </pattern>
163
+
164
+ ---
165
+
166
+ ## Email Templates
167
+
168
+ <pattern name="email-layouts">
169
+ <description>Shared layouts for consistent email branding</description>
170
+
171
+ **HTML Layout:**
172
+
173
+ ```erb
174
+ <%# app/views/layouts/mailer.html.erb %>
175
+ <!DOCTYPE html>
176
+ <html>
177
+ <head>
178
+ <meta charset="utf-8">
179
+ <style>
180
+ body {
181
+ font-family: Arial, sans-serif;
182
+ max-width: 600px;
183
+ margin: 0 auto;
184
+ color: #333;
185
+ }
186
+ .header {
187
+ background-color: #4F46E5;
188
+ color: white;
189
+ padding: 20px;
190
+ text-align: center;
191
+ }
192
+ .content {
193
+ padding: 20px;
194
+ }
195
+ .button {
196
+ display: inline-block;
197
+ padding: 12px 24px;
198
+ background-color: #4F46E5;
199
+ color: white;
200
+ text-decoration: none;
201
+ border-radius: 4px;
202
+ }
203
+ .footer {
204
+ padding: 20px;
205
+ text-align: center;
206
+ font-size: 12px;
207
+ color: #666;
208
+ }
209
+ </style>
210
+ </head>
211
+ <body>
212
+ <div class="header">
213
+ <h1>Your App</h1>
214
+ </div>
215
+ <div class="content">
216
+ <%= yield %>
217
+ </div>
218
+ <div class="footer">
219
+ <p>&copy; 2025 Your Company. All rights reserved.</p>
220
+ </div>
221
+ </body>
222
+ </html>
223
+ ```
224
+
225
+ **Text Layout:**
226
+
227
+ ```erb
228
+ <%# app/views/layouts/mailer.text.erb %>
229
+ ================================================================================
230
+ YOUR APP
231
+ ================================================================================
232
+
233
+ <%= yield %>
234
+
235
+ --------------------------------------------------------------------------------
236
+ © 2025 Your Company. All rights reserved.
237
+ ```
238
+
239
+ **Why:** Consistent branding across all emails. Inline CSS ensures styling works across email clients.
240
+ </pattern>
241
+
242
+ <pattern name="email-attachments">
243
+ <description>Attach files to emails (PDFs, CSVs, images)</description>
244
+
245
+ ```ruby
246
+ class ReportMailer < ApplicationMailer
247
+ def monthly_report(user, data)
248
+ @user = user
249
+
250
+ # Regular attachment
251
+ attachments["report.pdf"] = {
252
+ mime_type: "application/pdf",
253
+ content: generate_pdf(data)
254
+ }
255
+
256
+ # Inline attachment (for embedding in email body)
257
+ attachments.inline["logo.png"] = File.read(
258
+ Rails.root.join("app/assets/images/logo.png")
259
+ )
260
+
261
+ mail(to: user.email, subject: "Monthly Report")
262
+ end
263
+ end
264
+ ```
265
+
266
+ **In template:**
267
+
268
+ ```erb
269
+ <%# Reference inline attachment %>
270
+ <%= image_tag attachments["logo.png"].url %>
271
+ ```
272
+
273
+ **Why:** Attach reports, exports, or inline images. Inline attachments can be referenced in email body with image_tag.
274
+ </pattern>
275
+
276
+ <antipattern>
277
+ <description>Using *_path helpers instead of *_url in emails (broken links)</description>
278
+ <bad-example>
279
+
280
+ ```ruby
281
+ # ❌ WRONG - Relative path doesn't work in emails
282
+ def welcome_email(user)
283
+ @user = user
284
+ @login_url = login_path # => "/login" (relative path)
285
+ mail(to: user.email, subject: "Welcome")
286
+ end
287
+ ```
288
+
289
+ </bad-example>
290
+ <good-example>
291
+
292
+ ```ruby
293
+ # ✅ CORRECT - Full URL works in emails
294
+ def welcome_email(user)
295
+ @user = user
296
+ @login_url = login_url # => "https://example.com/login" (absolute URL)
297
+ mail(to: user.email, subject: "Welcome")
298
+ end
299
+
300
+ # Required configuration
301
+ # config/environments/production.rb
302
+ config.action_mailer.default_url_options = { host: "example.com", protocol: "https" }
303
+ ```
304
+
305
+ </good-example>
306
+
307
+ **Why bad:** Emails are viewed outside your application context, so relative paths don't work. Always use *_url helpers to generate absolute URLs.
308
+ </antipattern>
309
+
310
+ ---
311
+
312
+ ## Email Testing
313
+
314
+ <pattern name="letter-opener-setup">
315
+ <description>Preview emails in browser during development without sending</description>
316
+
317
+ **Configuration:**
318
+
319
+ ```ruby
320
+ # Gemfile
321
+ group :development do
322
+ gem "letter_opener"
323
+ end
324
+
325
+ # config/environments/development.rb
326
+ config.action_mailer.delivery_method = :letter_opener
327
+ config.action_mailer.default_url_options = { host: "localhost", port: 3000 }
328
+
329
+ # config/environments/production.rb
330
+ config.action_mailer.delivery_method = :smtp
331
+ config.action_mailer.smtp_settings = {
332
+ address: "smtp.sendgrid.net",
333
+ port: 587,
334
+ user_name: Rails.application.credentials.dig(:smtp, :username),
335
+ password: Rails.application.credentials.dig(:smtp, :password),
336
+ authentication: :plain,
337
+ enable_starttls_auto: true
338
+ }
339
+ config.action_mailer.default_url_options = { host: "example.com", protocol: "https" }
340
+ ```
341
+
342
+ **Why:** letter_opener opens emails in browser during development - no SMTP setup needed. Test email appearance without actually sending.
343
+ </pattern>
344
+
345
+ <pattern name="mailer-previews">
346
+ <description>Preview all email variations at /rails/mailers</description>
347
+
348
+ ```ruby
349
+ # test/mailers/previews/notification_mailer_preview.rb
350
+ class NotificationMailerPreview < ActionMailer::Preview
351
+ # Preview at http://localhost:3000/rails/mailers/notification_mailer/welcome_email
352
+ def welcome_email
353
+ user = User.first || User.new(name: "Test User", email: "test@example.com")
354
+ NotificationMailer.welcome_email(user)
355
+ end
356
+
357
+ def password_reset
358
+ user = User.first || User.new(name: "Test User", email: "test@example.com")
359
+ user.reset_token = "sample_token_123"
360
+ NotificationMailer.password_reset(user)
361
+ end
362
+
363
+ # Preview with different data
364
+ def welcome_email_long_name
365
+ user = User.new(name: "Christopher Alexander Montgomery III", email: "long@example.com")
366
+ NotificationMailer.welcome_email(user)
367
+ end
368
+ end
369
+ ```
370
+
371
+ **Why:** Mailer previews at /rails/mailers let you see all email variations without sending. Test different edge cases (long names, missing data, etc.).
372
+ </pattern>
373
+
374
+ <pattern name="mailer-testing">
375
+ <description>Test email delivery and content with ActionMailer::TestCase</description>
376
+
377
+ ```ruby
378
+ # test/mailers/notification_mailer_test.rb
379
+ class NotificationMailerTest < ActionMailer::TestCase
380
+ test "welcome_email sends with correct attributes" do
381
+ user = users(:alice)
382
+ email = NotificationMailer.welcome_email(user)
383
+
384
+ # Test delivery
385
+ assert_emails 1 do
386
+ email.deliver_now
387
+ end
388
+
389
+ # Test attributes
390
+ assert_equal [user.email], email.to
391
+ assert_equal ["noreply@example.com"], email.from
392
+ assert_equal "Welcome to Our App", email.subject
393
+
394
+ # Test content
395
+ assert_includes email.html_part.body.to_s, user.name
396
+ assert_includes email.text_part.body.to_s, user.name
397
+ assert_includes email.html_part.body.to_s, "Login Now"
398
+ end
399
+
400
+ test "delivers via background job" do
401
+ user = users(:alice)
402
+
403
+ assert_enqueued_with(job: ActionMailer::MailDeliveryJob, queue: "mailers") do
404
+ NotificationMailer.welcome_email(user).deliver_later(queue: :mailers)
405
+ end
406
+ end
407
+
408
+ test "password_reset includes reset link" do
409
+ user = users(:alice)
410
+ user.update!(reset_token: "test_token_123")
411
+ email = NotificationMailer.password_reset(user)
412
+
413
+ assert_includes email.html_part.body.to_s, "test_token_123"
414
+ assert_includes email.html_part.body.to_s, "password_reset"
415
+ end
416
+ end
417
+ ```
418
+
419
+ **Why:** Test email delivery, content, and background job enqueuing. Verify recipients, subjects, and that emails are queued properly.
420
+ </pattern>
421
+
422
+ ---
423
+
424
+ ## Email Configuration
425
+
426
+ <pattern name="environment-configuration">
427
+ <description>Configure ActionMailer for each environment</description>
428
+
429
+ **Development:**
430
+
431
+ ```ruby
432
+ # config/environments/development.rb
433
+ config.action_mailer.delivery_method = :letter_opener
434
+ config.action_mailer.perform_deliveries = true
435
+ config.action_mailer.raise_delivery_errors = true
436
+ config.action_mailer.default_url_options = { host: "localhost", port: 3000 }
437
+ ```
438
+
439
+ **Test:**
440
+
441
+ ```ruby
442
+ # config/environments/test.rb
443
+ config.action_mailer.delivery_method = :test
444
+ config.action_mailer.default_url_options = { host: "example.com" }
445
+ ```
446
+
447
+ **Production:**
448
+
449
+ ```ruby
450
+ # config/environments/production.rb
451
+ config.action_mailer.delivery_method = :smtp
452
+ config.action_mailer.perform_deliveries = true
453
+ config.action_mailer.raise_delivery_errors = false
454
+ config.action_mailer.default_url_options = {
455
+ host: ENV["APP_HOST"],
456
+ protocol: "https"
457
+ }
458
+
459
+ config.action_mailer.smtp_settings = {
460
+ address: ENV["SMTP_ADDRESS"],
461
+ port: ENV["SMTP_PORT"],
462
+ user_name: Rails.application.credentials.dig(:smtp, :username),
463
+ password: Rails.application.credentials.dig(:smtp, :password),
464
+ authentication: :plain,
465
+ enable_starttls_auto: true
466
+ }
467
+ ```
468
+
469
+ **Why:** Different configurations per environment. Development previews in browser, test stores emails in memory, production sends via SMTP.
470
+ </pattern>
471
+
472
+ ---
473
+
474
+ <testing>
475
+
476
+ ```ruby
477
+ # test/mailers/notification_mailer_test.rb
478
+ class NotificationMailerTest < ActionMailer::TestCase
479
+ setup do
480
+ @user = users(:alice)
481
+ end
482
+
483
+ test "welcome_email" do
484
+ email = NotificationMailer.welcome_email(@user)
485
+
486
+ assert_emails 1 { email.deliver_now }
487
+ assert_equal [@user.email], email.to
488
+ assert_equal ["noreply@example.com"], email.from
489
+ assert_match @user.name, email.html_part.body.to_s
490
+ assert_match @user.name, email.text_part.body.to_s
491
+ end
492
+
493
+ test "enqueues for async delivery" do
494
+ assert_enqueued_with(job: ActionMailer::MailDeliveryJob) do
495
+ NotificationMailer.welcome_email(@user).deliver_later
496
+ end
497
+ end
498
+
499
+ test "uses correct queue" do
500
+ assert_enqueued_with(job: ActionMailer::MailDeliveryJob, queue: "mailers") do
501
+ NotificationMailer.welcome_email(@user).deliver_later(queue: :mailers)
502
+ end
503
+ end
504
+ end
505
+
506
+ # test/system/email_delivery_test.rb
507
+ class EmailDeliveryTest < ApplicationSystemTestCase
508
+ test "sends welcome email after signup" do
509
+ visit signup_path
510
+ fill_in "Email", with: "new@example.com"
511
+ fill_in "Password", with: "password"
512
+ click_button "Sign Up"
513
+
514
+ assert_enqueued_emails 1
515
+ perform_enqueued_jobs
516
+
517
+ email = ActionMailer::Base.deliveries.last
518
+ assert_equal ["new@example.com"], email.to
519
+ assert_match "Welcome", email.subject
520
+ end
521
+ end
522
+ ```
523
+
524
+ </testing>
525
+
526
+ ---
527
+
528
+ <related-skills>
529
+ - rails-ai:jobs - Background job processing with SolidQueue
530
+ - rails-ai:views - Email templates and layouts
531
+ - rails-ai:testing - Testing email delivery
532
+ - rails-ai:project-setup - Environment-specific email configuration
533
+ </related-skills>
534
+
535
+ <resources>
536
+
537
+ **Official Documentation:**
538
+ - [Rails Guides - Action Mailer Basics](https://guides.rubyonrails.org/action_mailer_basics.html)
539
+
540
+ **Gems & Libraries:**
541
+ - [letter_opener](https://github.com/ryanb/letter_opener) - Preview emails in browser during development
542
+
543
+ **Tools:**
544
+ - [Email on Acid](https://www.emailonacid.com/) - Email testing across clients
545
+
546
+ **Email Service Providers:**
547
+ - [SendGrid Rails Guide](https://docs.sendgrid.com/for-developers/sending-email/rubyonrails)
548
+
549
+ </resources>