Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
b02eda3
Rails 8.1 support, CI is modernized
AlfonsoUceda Mar 19, 2026
9fbcb56
Gemfile version constraints are tightened
AlfonsoUceda Mar 19, 2026
d37317a
RuboCop target Ruby is updated, 2.5 to 3.3
AlfonsoUceda Mar 19, 2026
bf726f5
CHANGELOG trailing whitespace is removed
AlfonsoUceda Mar 19, 2026
9409b6c
CodeClimate configuration is removed
AlfonsoUceda Mar 19, 2026
4944cac
Gemspec version constraints are loosened
AlfonsoUceda Mar 19, 2026
b9fb24e
Local development database setup
AlfonsoUceda Mar 19, 2026
3f37de1
Development section in README is updated
AlfonsoUceda Mar 19, 2026
94daa6d
RuboCop configuration is modernized
AlfonsoUceda Mar 19, 2026
b6d706d
RuboCop offenses are corrected
AlfonsoUceda Mar 19, 2026
25a235b
Minimum Ruby version is set to 3.0
AlfonsoUceda Mar 19, 2026
33eead0
RuboCop offenses in specs are addressed
AlfonsoUceda Mar 19, 2026
b99773f
Database configuration is consolidated into config/database.yml
AlfonsoUceda Mar 19, 2026
67b176a
CHANGELOG is updated with meaningful changes from this branch
AlfonsoUceda Mar 19, 2026
60a3eae
.ruby-version is tracked
AlfonsoUceda Mar 19, 2026
959105a
CI matrix fail-fast is disabled
AlfonsoUceda Mar 19, 2026
dab618b
Rails 6.1 support is removed
AlfonsoUceda Mar 19, 2026
a66fb96
sqlite3 version is pinned for Rails 7.0 gemfile
AlfonsoUceda Mar 19, 2026
78a2243
lambda(&:nil?) in specs is replaced with explicit lambdas
AlfonsoUceda Mar 19, 2026
5e4946c
Explicit ruby-version in RuboCop workflow is removed
AlfonsoUceda Mar 20, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 0 additions & 4 deletions .codeclimate.yml

This file was deleted.

16 changes: 8 additions & 8 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,22 @@ jobs:
runs-on: ubuntu-latest

strategy:
fail-fast: false

matrix:
include:
- ruby: '2.7'
gemfile: rails61
- ruby: '3.0'
gemfile: rails70
- ruby: '3.4'
gemfile: rails80
- ruby: '4.0'
gemfile: rails81
- ruby: '4.0'
gemfile: railsmaster

services:
postgres:
image: postgres:9.6
image: postgres
env:
POSTGRES_USER: root
POSTGRES_DB: database_validations_test
Expand All @@ -38,7 +40,7 @@ jobs:
- 5432:5432

mysql:
image: mysql:5.6
image: mysql
env:
MYSQL_ROOT_HOST: '%'
MYSQL_ROOT_PASSWORD: test
Expand All @@ -61,16 +63,14 @@ jobs:
BUNDLE_GEMFILE: gemfiles/${{ matrix.gemfile }}.gemfile

steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6

- name: Set up Ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: ${{ matrix.ruby }}
bundler-cache: true

- name: Use ${{ matrix.gemfile }} as the Gemfile
run: bundle config --global gemfile ${{ matrix.gemfile }}
bundler: latest

- name: Run tests
run: bundle exec rspec
26 changes: 26 additions & 0 deletions .github/workflows/rubocop.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
name: Rubocop

on:
push:
branches: [master, main]
pull_request:

jobs:
rubocop:
runs-on: ubuntu-latest

permissions:
contents: read
id-token: write

steps:
- uses: actions/checkout@v6

- name: Set up Ruby
uses: ruby/setup-ruby@v1
with:
bundler-cache: true

- name: Lint Ruby code with RuboCop
run: |
bundle exec rubocop
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,4 @@ example/log
example/Gemfile.lock
example/config/database.yml

.ruby-version
.ruby-gemset
13 changes: 12 additions & 1 deletion .rubocop-todo.yml
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
Metrics/LineLength:
Layout/LineLength:
Max: 140
Exclude:
- 'benchmarks/*.rb'

Metrics/MethodLength:
Max: 15
Exclude:
- Rakefile

Metrics/BlockLength:
Exclude:
- 'spec/**/*_spec.rb'
- 'benchmarks/*.rb'
- Rakefile

Style/Documentation:
Enabled: false
Expand All @@ -30,3 +33,11 @@ Style/Semicolon:
Style/NumericPredicate:
Exclude:
- 'benchmarks/*.rb'

Style/MixinUsage:
Exclude:
- Rakefile

RSpec/SpecFilePathFormat:
Exclude:
- spec/rubocop/**/*.rb
17 changes: 15 additions & 2 deletions .rubocop.yml
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
inherit_from: .rubocop-todo.yml
require:
plugins:
- rubocop-rspec

AllCops:
NewCops: disable
SuggestExtensions: false
DisplayCopNames: true
TargetRubyVersion: 2.5
TargetRubyVersion: 3.0
Include:
- '**/*.rb'
- 'Gemfile'
Expand All @@ -24,3 +26,14 @@ Style/FrozenStringLiteralComment:

RSpec/MultipleExpectations:
Enabled: false

Naming/VariableNumber:
Enabled: false

RSpec/ExampleWording:
Enabled: false


Lint/ConstantDefinitionInBlock:
Exclude:
- 'benchmarks/*.rb'
1 change: 1 addition & 0 deletions .ruby-version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
3.4
18 changes: 12 additions & 6 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
# Changelog

## [1.2.0] - 07-02-2025
## [x.x.x] - DD-MM-YYY
### Improvements

- Add Rails 8.1 support
- Set minimum Ruby version to 3.0
- Loosen gemspec development dependency version constraints
- Modernize CI configuration and add dedicated RuboCop workflow
- Consolidate database configuration into `config/database.yml`
- Add local development database setup with Docker Compose
- Fix RuboCop integration. Thank to [Evgeny Matveyev](https://github.com/evgeny-matveev) for fixing it.

## [1.1.1] - 14-03-2022
Expand Down Expand Up @@ -38,7 +44,7 @@
## [0.9.2] - 16-09-20
### Improvements

- Fix a warning message from newest Ruby version
- Fix a warning message from newest Ruby version

## [0.9.1] - 24-06-20
### Improvements
Expand All @@ -56,14 +62,14 @@

## [0.8.10] - 21-02-19
### Improvements
- Internal improvements
- Internal improvements
- We raise an error if `scope` or `where` options are missed for the `validates_db_uniqueness_of`

## [0.8.9] - 13-02-19
### Bugs
- Hot-fix for `validate_db_uniqueness_of` RSpec matcher

## (removed) [0.8.8] - 13-02-19
## (removed) [0.8.8] - 13-02-19
### Bugs
- Hot-fix for `validates_db_uniqueness_of`

Expand All @@ -89,15 +95,15 @@

## [0.8.2] - 10-01-18
### Bugs
- Fix RuboCop cop for `validates_db_uniqueness_of` to catch `validates_uniqueness_of` definition too.
- Fix RuboCop cop for `validates_db_uniqueness_of` to catch `validates_uniqueness_of` definition too.

## [0.8.1] - 09-01-18
### Features
- Add RuboCop cop for `db_belongs_to` and `validates_db_uniqueness_of`

## [0.8.0] - 30-11-18
### Features
- Add `db_belongs_to`
- Add `db_belongs_to`

## [0.7.3] - 2018-10-18
### Features
Expand Down
23 changes: 19 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ if you want to skip it in some cases. (For example, when you run migrations.) _N

The validation has an option `:rescue` with two values:
- `:default` (default option) that follows default ActiveRecord behavior. It respects `validate: false` option for `save/save!` (for example, this is being used for nested associations)
- `:always` that catches database constraint errors and turns them to ActiveRecord validations filling `.errors` properly.
- `:always` that catches database constraint errors and turns them to ActiveRecord validations filling `.errors` properly.

You may want to use `rescue: :always` in case you save nested associations with `accepts_nested_attributes_for` helper and you want the validation to happen automatically when a user
provides duplicated data in the same request.
Expand Down Expand Up @@ -270,10 +270,25 @@ require:

## Development

You need to have installed and running `postgresql` and `mysql`.
And for each adapter manually create a database called `database_validations_test` accessible by your local user.
The easiest way to get started is with Docker. A `docker-compose.yaml` is
included that runs PostgreSQL and MySQL with preconfigured test databases:

Then, run `rake spec` to run the tests.
```bash
docker compose up -d
```

Then create the test databases and run the specs:

```bash
rake db:all:create
rake spec
```

To drop the test databases:

```bash
rake db:all:drop
```

To check the conformance with the style guides, run:

Expand Down
53 changes: 53 additions & 0 deletions Rakefile
Original file line number Diff line number Diff line change
@@ -1,6 +1,59 @@
require 'bundler/gem_tasks'
require 'rspec/core/rake_task'
require 'active_record'
require_relative 'config/database_config'

RSpec::Core::RakeTask.new(:spec)

task default: :spec

DATABASE_CONFIGURATIONS = DatabaseConfig.load

include ActiveRecord::Tasks

DatabaseTasks.database_configuration = DATABASE_CONFIGURATIONS
DatabaseTasks.db_dir = 'db'
DatabaseTasks.migrations_paths = []
DatabaseTasks.root = File.dirname(__FILE__)
DatabaseTasks.env = ENV.fetch('DB', 'postgresql')

task :environment do
ActiveRecord::Base.configurations = DATABASE_CONFIGURATIONS
ActiveRecord::Base.establish_connection(DatabaseTasks.env.to_sym)
end

load 'active_record/railties/databases.rake'

namespace :db do
namespace :all do
desc 'Create both PostgreSQL and MySQL test databases'
task :create do
failures = []
DATABASE_CONFIGURATIONS.each do |name, config|
next if config['adapter'] == 'sqlite3'

puts "Creating #{name} database..."
ActiveRecord::Tasks::DatabaseTasks.create(config)
rescue StandardError => e
failures << name
warn " Failed to create #{name}: #{e.message}"
end
abort "Failed to create: #{failures.join(', ')}" if failures.any?
end

desc 'Drop both PostgreSQL and MySQL test databases'
task :drop do
failures = []
DATABASE_CONFIGURATIONS.each do |name, config|
next if config['adapter'] == 'sqlite3'

puts "Dropping #{name} database..."
ActiveRecord::Tasks::DatabaseTasks.drop(config)
rescue StandardError => e
failures << name
warn " Failed to drop #{name}: #{e.message}"
end
abort "Failed to drop: #{failures.join(', ')}" if failures.any?
end
end
end
17 changes: 17 additions & 0 deletions config/database.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
postgresql:
adapter: postgresql
database: database_validations_test
host: <%= ENV['DB_HOST'] || '127.0.0.1' %>
username: <%= ENV['DB_USER'] || 'database_validations' %>
password: <%= ENV['DB_PASSWORD'] || 'database_validations' %>

mysql:
adapter: mysql2
database: database_validations_test
host: <%= ENV['DB_HOST'] || '127.0.0.1' %>
username: <%= ENV['DB_USER'] || 'root' %>
password: <%= ENV['DB_PASSWORD'] || 'database_validations' %>

sqlite:
adapter: sqlite3
database: ':memory:'
12 changes: 12 additions & 0 deletions config/database_config.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
require 'erb'
require 'yaml'

module DatabaseConfig
def self.load(symbolize_keys: false)
yaml_path = File.expand_path('database.yml', __dir__)
yaml_content = ERB.new(File.read(yaml_path)).result
configs = YAML.safe_load(yaml_content)
configs = configs.transform_values { |v| v.transform_keys(&:to_sym) } if symbolize_keys
configs
end
end
19 changes: 10 additions & 9 deletions database_validations.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ lib = File.expand_path('lib', __dir__)
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
require 'database_validations/version'

Gem::Specification.new do |spec| # rubocop:disable Metrics/BlockLength
Gem::Specification.new do |spec|
spec.name = 'database_validations'
spec.version = DatabaseValidations::VERSION
spec.authors = ['Evgeniy Demin']
Expand All @@ -19,17 +19,18 @@ and ActiveRecord validations with better performance and consistency."
spec.license = 'MIT'
spec.files = Dir['lib/**/*']
spec.require_paths = ['lib']
spec.required_ruby_version = '>= 3.0.0'

spec.add_dependency 'activerecord', '>= 4.2.0'
spec.add_dependency 'activerecord', '>= 7.0.0'

spec.add_development_dependency 'benchmark-ips', '~> 2.7'
spec.add_development_dependency 'bundler', '>= 2.0'
spec.add_development_dependency 'db-query-matchers', '>= 0.9'
spec.add_development_dependency 'benchmark-ips'
spec.add_development_dependency 'bundler'
spec.add_development_dependency 'db-query-matchers'
spec.add_development_dependency 'mysql2'
spec.add_development_dependency 'pg'
spec.add_development_dependency 'rake', '~> 13.0'
spec.add_development_dependency 'rspec', '~> 3.0'
spec.add_development_dependency 'rubocop', '~> 1.80'
spec.add_development_dependency 'rubocop-rspec', '~> 3.8'
spec.add_development_dependency 'rake'
spec.add_development_dependency 'rspec'
spec.add_development_dependency 'rubocop'
spec.add_development_dependency 'rubocop-rspec'
spec.add_development_dependency 'sqlite3'
end
Loading