| name | rails-transactions |
| description | Implement database transactions for data consistency and atomicity. Use when operations must succeed or fail together, coordinating multiple database operations, or ensuring data integrity across models. |
Rails Transaction Management Specialist
Specialized in implementing safe, atomic database transactions.
When to Use This Skill
- Operations that must all succeed or all fail (e.g., fund transfers)
- Coordinating updates across multiple models
- Ensuring data consistency and integrity
- Rollback scenarios on error
- Complex business operations requiring atomicity
Core Principles
- Atomicity: All operations succeed or all fail
- Consistency: Database remains in valid state
- Isolation: Transactions don't interfere with each other
- Durability: Committed changes persist
Implementation Guidelines
Basic Transaction
def transfer_funds(from_account, to_account, amount)
ActiveRecord::Base.transaction do
from_account.withdraw!(amount)
to_account.deposit!(amount)
Transfer.create!(
from: from_account,
to: to_account,
amount: amount
)
end
end
Transaction with Explicit Rollback
def process_order(order)
ActiveRecord::Base.transaction do
order.update!(status: 'processing')
payment = charge_payment(order)
# WHY: Rollback if payment fails
raise ActiveRecord::Rollback unless payment.successful?
order.update!(status: 'confirmed')
inventory.decrement_stock(order.items)
send_confirmation_email(order)
end
end
Nested Transactions
def create_company_with_users(company_data, users_data)
ActiveRecord::Base.transaction do
company = Company.create!(company_data)
# WHY: Inner transaction for user creation
users_data.each do |user_data|
ActiveRecord::Base.transaction(requires_new: true) do
User.create!(user_data.merge(company: company))
end
end
company
end
end
Transaction with Locking
def reserve_seat(seat_id, user_id)
ActiveRecord::Base.transaction do
# WHY: Lock seat record to prevent race conditions
seat = Seat.lock.find(seat_id)
raise 'Seat already reserved' if seat.reserved?
seat.update!(reserved: true, user_id: user_id)
Reservation.create!(seat: seat, user_id: user_id)
end
end
Isolation Levels
def generate_report_with_consistent_data
# WHY: Use REPEATABLE READ to ensure data consistency during report generation
ActiveRecord::Base.transaction(isolation: :repeatable_read) do
sales_data = Sale.all.to_a
inventory_data = Inventory.all.to_a
generate_report(sales_data, inventory_data)
end
end
Error Handling in Transactions
def process_batch(items)
results = { success: [], failed: [] }
ActiveRecord::Base.transaction do
items.each do |item|
begin
process_item(item)
results[:success] << item
rescue => e
# WHY: Log error but continue processing other items
Rails.logger.error("Failed to process item #{item.id}: #{e.message}")
results[:failed] << { item: item, error: e.message }
end
end
end
results
end
Tools to Use
Read: Read existing transaction codeEdit: Modify transaction logicBash: Run tests with transaction scenariosmcp__serena__find_symbol: Find transaction usage
Bash Commands
# Run transaction tests
bundle exec rspec spec/models/account_spec.rb
# Test in Rails console
bundle exec rails console
Workflow
- Identify Atomic Operations: Determine what must succeed/fail together
- Write Tests First: Test both success and failure scenarios
- Wrap in Transaction: Use
ActiveRecord::Base.transaction - Add Error Handling: Handle exceptions appropriately
- Test Rollback: Verify rollback works correctly
- Consider Locking: Add locks if race conditions possible
Related Skills
rails-service-objects: Transactions often used in servicesrails-error-handling: Error handling within transactionsrails-model-design: Understanding model operations
Coding Standards
TDD Workflow
Follow TDD Workflow
Key Reminders
- Always use transactions for multi-model operations
- Use
raise ActiveRecord::Rollbackfor explicit rollback - Consider
lockfor race condition prevention - Test both success and failure scenarios
- Be aware of transaction nesting behavior
- Use appropriate isolation levels for specific needs
- Avoid long-running operations in transactions