Feature Proposal: Enable Custom Validation Contexts

Currently, we can validate a model using the valid? or validate methods provided by ActiveModel::Validations. These methods accept an optional validation context argument, which allows us to dynamically process or ignore certain validations based on the context passed:

class User < ApplicationRecord
  validates :email, uniqueness: true, except_on: :skip_validations
end

User.create(name: 'Test User 1', email: 'test@example.com')
@user = User.build(name: 'Test User 2', email: 'test@example.com')
@user.valid?(:skip_validations) # => true

This works well when you’re explicitly calling valid? in your workflow. However, when relying on methods like find_or_create_by, create, update, etc., there’s no way to pass these contexts, which is problematic. Therefore, I propose adding the ability to set the validation context before calling save operations:

class User < ApplicationRecord
  validates :email, uniqueness: true, except_on: :skip_validations
end

User.create(name: 'Test User 1', email: 'test@example.com')

User.create(name: 'Test User 2', email: 'test@example.com') do |user|
  user.validation_context = :skip_validations
end

# or
User.create_or_find_by(email: 'test@example.com') do |user|
  user.name = 'Test User 2'
  user.validation_context = :skip_validations
end

I see significant value in this proposal, especially if your codebase uses methods like find_or_create_by. This method specifically relies on errors thrown when database constraints fail, not when record validations fail. With validation contexts, we could allow validations to run normally in most cases, but selectively skip them in specific workflows.

Here’s a PR built for this particular proposal