Cursor Is Breaking Your Rails Migrations (Here’s How to Fix It)

Adrian Yonan 8 May 2026


AI-assisted development tools like Cursor and Claude Code are quickly becoming part of everyday Rails workflows. They’re great at scaffolding code, speeding up repetitive tasks, and helping you stay in flow. Used well, they can significantly improve productivity and reduce the time spent on boilerplate.

But just like any tool, they come with trade-offs.

In our case, this caused a staging deployment to fail when migrations ran out of order, leaving the application expecting a table that hadn’t been created yet.

This post covers a real-world issue our team ran into using Cursor with Ruby on Rails--specifically around migrations and model generation-and how we fixed it using Cursor rules.



The Problem: Broken Rails Conventions


# db/migrate/20240502000001_create_users.rb
class CreateUsers < ActiveRecord::Migration[7.0]
def change
create_table :users do |t|
t.string :email
t.string :name
t.string :encrypted_password
t.boolean :active, default: true
t.timestamps
end
end
end

At first glance, this looks completely fine. The migration runs, the table is created, and nothing appears broken.


But there are two underlying issues here.




1. Migration Timestamp Issues


Cursor often generates migrations with incorrect or static timestamps, such as:


20240502000001_create_users.rb

Instead of using the current timestamp, it inserts an outdated value.


Why this is a problem


Rails uses timestamps to determine the execution order of migrations. If a migration is generated with an older timestamp:



  • It gets inserted into the middle of existing migrations based on its timestamp.

  • Execution order becomes inconsistent

  • Schema state can become unpredictable

  • Deployments may behave differently across environments

  • New developers may encounter failures when setting up the project


This isn’t just untidy - it introduces real risk.




2. Incorrect Generator Usage


Cursor also tends to generate tables using:


rails generate migration CreateUsers

Instead of:


rails generate model User

Why this matters


Using the migration generator directly bypasses important parts of the Rails workflow:



  • No model file is created

  • No RSpec files are generated

  • No FactoryBot factories are created

  • Naming conventions can drift


You end up either doing manual cleanup or missing pieces entirely. Over time, this leads to inconsistency across the codebase.




The Importance of Rails Conventions


Rails is built around convention over configuration. The ecosystem assumes a predictable structure, and most tools - RSpec, FactoryBot, linters - build on top of that.


When those conventions are broken, even in small ways, the impact compounds:



  • Migration history becomes harder to reason about

  • Environments drift apart

  • Bugs become harder to trace

  • Onboarding new developers gets more difficult


AI tools don’t understand your project’s workflow - they optimise for “valid code,” not “correct behaviour.”




The Solution: Cursor Rules


Cursor supports project-level rule files that guide how it generates code. These rules live inside a .cursor directory and are automatically included in its context.


Think of them as guardrails that keep the AI aligned with your conventions.




Step 1: Create a Migration Rule File


Create the following file:


.cursor/rules/migration-creation.mdc

Add:


---
description: Rails migration creation conventions
globs: db/migrate/*.rb

alwaysApply: false

Rails Migration Creation Rules

1. Timestamp Integrity

  • Always generate migrations with a timestamp greater than the latest existing file in db/migrate.
  • Before creating a migration, inspect the current latest timestamp.
  • Never generate out-of-order migrations.
  • Do not use hardcoded or static timestamps.

2. Table Creation

  • When creating a new table, always use:

rails generate model ModelName

  • Never use:

rails generate migration CreateModelName

  • The model generator ensures:
    • Proper timestamp ordering
    • Model file creation
    • Test file generation (RSpec)
    • FactoryBot setup (if configured)
    • Correct naming conventions

3. Naming Conventions

  • Follow standard Rails naming:
    • CreateUsers
    • AddFieldToUsers
    • RemoveColumnFromOrders
  • Use clear, descriptive names that reflect the change.

4. Safety Checks

Before generating any migration:

  • Confirm no newer migration exists
  • Ensure no naming conflicts
  • Avoid duplicate or redundant migrations
  • Prefer reversible migrations where possible

This ensures Cursor generates code that aligns with Rails conventions - not just syntactically valid output.


Step 2: Register the Rule

Create or Update:

.cursor/instructions.mdc

Then add the following inside it:

---
description: Core development guidelines for Winboard
globs:
alwaysApply: true
---


Project Name Development Guidelines

Specialized Rules

Area: Migration Creation Patterns

Rule File: migration-creation.mdc


This keeps your rules organised and makes it easy to expand later.




Conclusion


If you're using AI tools in a codebase, don't rely on default behaviour. Define your expectations early.


Start with migrations, but extend this approach to:



  • Service objects

  • Background jobs

  • API patterns

  • Testing conventions


Rails thrives on consistency. If you want the benefit of AI without compromising your codebase, you need to encode those conventions explicitly.


Cursor rules are a simple and effective way to do exactly that.


AI won’t follow your conventions unless you make them explicit.