Back to Skills

vanilla-rails-jobs

verified

Use when writing background jobs or async operations - enforces thin job wrappers (3-5 lines) that delegate to models using _later/_now naming pattern

View on GitHub

Marketplace

zemptime-marketplace

ZempTime/zemptime-marketplace

Plugin

vanilla-rails

Repository

ZempTime/zemptime-marketplace
1stars

vanilla-rails/skills/jobs/SKILL.md

Last Verified

January 20, 2026

Install Skill

Select agents to install to:

Scope:
npx add-skill https://github.com/ZempTime/zemptime-marketplace/blob/main/vanilla-rails/skills/jobs/SKILL.md -a claude-code --skill vanilla-rails-jobs

Installation paths:

Claude
.claude/skills/vanilla-rails-jobs/
Powered by add-skill CLI

Instructions

# Vanilla Rails Jobs

**Jobs are thin wrappers (3-5 lines). ALL business logic lives in models.**

## The Pattern

```ruby
# Model concern - WHERE THE LOGIC LIVES
module Card::ClosureNotifications
  extend ActiveSupport::Concern

  included do
    after_update :notify_watchers_later, if: :just_closed?
  end

  # _later: Enqueues the job
  def notify_watchers_later
    Card::ClosureNotificationJob.perform_later(self)
  end

  # _now: Contains ALL business logic
  def notify_watchers_now
    watchers.each do |watcher|
      CardMailer.closure_notification(watcher, self).deliver_now
      Notification.create!(user: watcher, card: self, action: 'closed')
    end
  end

  private
    def just_closed?
      saved_change_to_status? && closed?
    end
end

# Job - ONLY delegates (3 lines)
class Card::ClosureNotificationJob < ApplicationJob
  def perform(card)
    card.notify_watchers_now
  end
end
```

## Why Jobs Stay Thin

**Testability:** Test `_now` synchronously (no job infrastructure needed)
**Reusability:** Call `_now` in console, tests, anywhere
**Debuggability:** Stack traces point to model, not job framework

## Naming Convention

| Method | Purpose |
|--------|---------|
| `action_later` | Enqueues job |
| `action_now` | Actual logic (called by job, ALWAYS create for testing) |
| `action` | No async version |

**Flow:** Callback → `_later` → enqueue job → job calls `_now` → logic executes

## Red Flags - STOP and Fix

If you see ANY of these, you're doing it wrong:

- [ ] Job longer than 5 lines (except ActiveJob config like `retry_on`)
- [ ] Business logic in job (queries, conditionals, loops)
- [ ] Job creates/updates records
- [ ] Job sends emails directly
- [ ] Job calls multiple models directly
- [ ] No `_later`/`_now` naming
- [ ] Passing IDs to job instead of objects
- [ ] Logic split between job and model
- [ ] Job has error handling beyond `retry_on`/`discard_on`
- [ ] Model missing `_now` method ("I don't need it")

**ALL of these mean: Move logic to mo

Validation Details

Front Matter
Required Fields
Valid Name Format
Valid Description
Has Sections
Allowed Tools
Instruction Length:
6619 chars

Issues Found:

  • name_directory_mismatch