├── .github └── workflows │ └── test.yml ├── .gitignore ├── .ruby-version ├── CHANGELOG.md ├── Gemfile ├── Gemfile.6.1.pg ├── Gemfile.6.1.pg.lock ├── Gemfile.7.0.pg ├── Gemfile.7.0.pg.lock ├── Gemfile.7.1.pg ├── Gemfile.7.1.pg.lock ├── Gemfile.7.2.pg ├── Gemfile.7.2.pg.lock ├── Gemfile.8.0.pg ├── Gemfile.8.0.pg.lock ├── Gemfile.lock ├── LICENSE ├── README.md ├── Rakefile ├── has_defaults.gemspec ├── lib ├── has_defaults.rb └── has_defaults │ ├── active_record_ext.rb │ └── version.rb └── spec ├── has_defaults └── active_record_ext_spec.rb ├── spec_helper.rb └── support ├── database.github.yml ├── database.rb ├── database.sample.yml ├── database.travis.yml └── models.rb /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Tests 3 | 'on': 4 | push: 5 | branches: 6 | - master 7 | pull_request: 8 | branches: 9 | - master 10 | jobs: 11 | test_pg: 12 | runs-on: ubuntu-24.04 13 | services: 14 | postgres: 15 | image: postgres 16 | env: 17 | POSTGRES_PASSWORD: postgres 18 | options: "--health-cmd pg_isready --health-interval 10s --health-timeout 5s 19 | --health-retries 5" 20 | ports: 21 | - 5432:5432 22 | strategy: 23 | fail-fast: false 24 | matrix: 25 | include: 26 | - ruby: 2.7.4 27 | gemfile: Gemfile.6.1.pg 28 | - ruby: 2.7.4 29 | gemfile: Gemfile.7.0.pg 30 | - ruby: 2.7.4 31 | gemfile: Gemfile.7.1.pg 32 | - ruby: 3.2.1 33 | gemfile: Gemfile.6.1.pg 34 | - ruby: 3.2.1 35 | gemfile: Gemfile.7.0.pg 36 | - ruby: 3.2.1 37 | gemfile: Gemfile.8.0.pg 38 | - ruby: 3.3.6 39 | gemfile: Gemfile.7.0.pg 40 | - ruby: 3.3.6 41 | gemfile: Gemfile.7.1.pg 42 | - ruby: 3.3.6 43 | gemfile: Gemfile.7.2.pg 44 | - ruby: 3.3.6 45 | gemfile: Gemfile.8.0.pg 46 | - ruby: 3.4.1 47 | gemfile: Gemfile.7.1.pg 48 | - ruby: 3.4.1 49 | gemfile: Gemfile.7.2.pg 50 | - ruby: 3.4.1 51 | gemfile: Gemfile.8.0.pg 52 | env: 53 | BUNDLE_GEMFILE: "${{ matrix.gemfile }}" 54 | steps: 55 | - uses: actions/checkout@v2 56 | - name: Install ruby 57 | uses: ruby/setup-ruby@v1 58 | with: 59 | ruby-version: "${{ matrix.ruby }}" 60 | - name: Setup database 61 | run: | 62 | sudo apt-get install -y postgresql-client 63 | PGPASSWORD=postgres psql -c 'create database test;' -U postgres -p 5432 -h localhost 64 | - name: Bundle 65 | run: | 66 | gem install bundler:2.2.26 67 | bundle install --no-deployment 68 | - name: Run tests 69 | run: bundle exec rspec 70 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/* 2 | spec/support/database.yml 3 | pkg 4 | -------------------------------------------------------------------------------- /.ruby-version: -------------------------------------------------------------------------------- 1 | 2.7.4 2 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | All notable changes to this project will be documented in this file. 3 | 4 | This project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). 5 | 6 | 7 | ## Unreleased 8 | 9 | ### Breaking changes 10 | 11 | ### Compatible changes 12 | 13 | 14 | ## 1.3.0 - 2025-01-29 15 | 16 | ### Breaking changes 17 | - Drop support for Rails < 6.1. This also drops support for MySQL, which had only been present for Rails < 6. 18 | 19 | ### Compatible changes 20 | 21 | - Add support for Rails 7.1, 7.2 and Ruby 3.3 22 | - Add support for Rails 8.0 and Ruby 3.4 23 | 24 | 25 | ## 1.2.1 - 2024-10-25 26 | 27 | ### Compatible changes 28 | 29 | * Follow recommended way to extend Railties 30 | 31 | 32 | ## 1.2.0 - 2023-03-15 33 | 34 | ### Breaking changes 35 | 36 | * Drop support for Ruby 2.5 with Rails 6.1 37 | 38 | ### Compatible changes 39 | 40 | * Add support for Ruby 3.2 41 | 42 | 43 | ## 1.1.1 - 2022-03-09 44 | 45 | ### Breaking changes 46 | 47 | ### Compatible changes 48 | 49 | * Activate Rubygems MFA 50 | 51 | 52 | ## 1.1.0 - 2022-01-20 53 | 54 | ### Breaking changes 55 | 56 | ### Compatible changes 57 | 58 | * Add support for Rails 7 (see [#7](https://github.com/makandra/has_defaults/issues/7)) 59 | 60 | 61 | ## 1.0.0 - 2021-08-25 62 | 63 | ### Breaking changes 64 | 65 | - Drop support for Ruby 1.8.7 and Rails 2.3 66 | 67 | ### Compatible changes 68 | 69 | - Added this CHANGELOG file. 70 | - Add support for Rails 6.1 71 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | Gemfile.7.0.pg -------------------------------------------------------------------------------- /Gemfile.6.1.pg: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | # Runtime dependencies 4 | gem 'activerecord', '~>6.1.3' 5 | gem 'pg', '>=1.3' 6 | 7 | # Development dependencies 8 | gem 'rake' 9 | gem 'database_cleaner' 10 | gem 'rspec', '~>3.5' 11 | gem 'gemika', '>=0.8.1' 12 | gem 'pry-byebug' 13 | 14 | # Gem under test 15 | gem 'has_defaults', path: '.' 16 | -------------------------------------------------------------------------------- /Gemfile.6.1.pg.lock: -------------------------------------------------------------------------------- 1 | PATH 2 | remote: . 3 | specs: 4 | has_defaults (1.3.0) 5 | activerecord 6 | 7 | GEM 8 | remote: https://rubygems.org/ 9 | specs: 10 | activemodel (6.1.3) 11 | activesupport (= 6.1.3) 12 | activerecord (6.1.3) 13 | activemodel (= 6.1.3) 14 | activesupport (= 6.1.3) 15 | activesupport (6.1.3) 16 | concurrent-ruby (~> 1.0, >= 1.0.2) 17 | i18n (>= 1.6, < 2) 18 | minitest (>= 5.1) 19 | tzinfo (~> 2.0) 20 | zeitwerk (~> 2.3) 21 | byebug (11.1.3) 22 | coderay (1.1.3) 23 | concurrent-ruby (1.1.8) 24 | database_cleaner (2.0.1) 25 | database_cleaner-active_record (~> 2.0.0) 26 | database_cleaner-active_record (2.0.0) 27 | activerecord (>= 5.a) 28 | database_cleaner-core (~> 2.0.0) 29 | database_cleaner-core (2.0.1) 30 | diff-lcs (1.4.4) 31 | gemika (0.8.1) 32 | i18n (1.8.9) 33 | concurrent-ruby (~> 1.0) 34 | method_source (1.0.0) 35 | minitest (5.14.4) 36 | pg (1.4.5) 37 | pry (0.14.2) 38 | coderay (~> 1.1) 39 | method_source (~> 1.0) 40 | pry-byebug (3.8.0) 41 | byebug (~> 11.0) 42 | pry (~> 0.10) 43 | rake (13.0.3) 44 | rspec (3.10.0) 45 | rspec-core (~> 3.10.0) 46 | rspec-expectations (~> 3.10.0) 47 | rspec-mocks (~> 3.10.0) 48 | rspec-core (3.10.1) 49 | rspec-support (~> 3.10.0) 50 | rspec-expectations (3.10.1) 51 | diff-lcs (>= 1.2.0, < 2.0) 52 | rspec-support (~> 3.10.0) 53 | rspec-mocks (3.10.2) 54 | diff-lcs (>= 1.2.0, < 2.0) 55 | rspec-support (~> 3.10.0) 56 | rspec-support (3.10.2) 57 | tzinfo (2.0.4) 58 | concurrent-ruby (~> 1.0) 59 | zeitwerk (2.4.2) 60 | 61 | PLATFORMS 62 | ruby 63 | 64 | DEPENDENCIES 65 | activerecord (~> 6.1.3) 66 | database_cleaner 67 | gemika (>= 0.8.1) 68 | has_defaults! 69 | pg (>= 1.3) 70 | pry-byebug 71 | rake 72 | rspec (~> 3.5) 73 | 74 | BUNDLED WITH 75 | 2.3.26 76 | -------------------------------------------------------------------------------- /Gemfile.7.0.pg: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | # Runtime dependencies 4 | gem 'activerecord', '~>7.0.1' 5 | gem 'pg', '>=1.3' 6 | 7 | # Development dependencies 8 | gem 'rake' 9 | gem 'database_cleaner' 10 | gem 'rspec', '~>3.5' 11 | gem 'gemika', '>=0.8.1' 12 | gem 'pry-byebug', '>=3.10.1' 13 | 14 | # Gem under test 15 | gem 'has_defaults', path: '.' 16 | -------------------------------------------------------------------------------- /Gemfile.7.0.pg.lock: -------------------------------------------------------------------------------- 1 | PATH 2 | remote: . 3 | specs: 4 | has_defaults (1.3.0) 5 | activerecord 6 | 7 | GEM 8 | remote: https://rubygems.org/ 9 | specs: 10 | activemodel (7.0.4.2) 11 | activesupport (= 7.0.4.2) 12 | activerecord (7.0.4.2) 13 | activemodel (= 7.0.4.2) 14 | activesupport (= 7.0.4.2) 15 | activesupport (7.0.4.2) 16 | concurrent-ruby (~> 1.0, >= 1.0.2) 17 | i18n (>= 1.6, < 2) 18 | minitest (>= 5.1) 19 | tzinfo (~> 2.0) 20 | byebug (11.1.3) 21 | coderay (1.1.3) 22 | concurrent-ruby (1.2.2) 23 | database_cleaner (2.0.1) 24 | database_cleaner-active_record (~> 2.0.0) 25 | database_cleaner-active_record (2.0.1) 26 | activerecord (>= 5.a) 27 | database_cleaner-core (~> 2.0.0) 28 | database_cleaner-core (2.0.1) 29 | diff-lcs (1.5.0) 30 | gemika (0.8.4) 31 | i18n (1.12.0) 32 | concurrent-ruby (~> 1.0) 33 | method_source (1.0.0) 34 | minitest (5.17.0) 35 | pg (1.4.6) 36 | pry (0.14.2) 37 | coderay (~> 1.1) 38 | method_source (~> 1.0) 39 | pry-byebug (3.10.1) 40 | byebug (~> 11.0) 41 | pry (>= 0.13, < 0.15) 42 | rake (13.0.6) 43 | rspec (3.10.0) 44 | rspec-core (~> 3.10.0) 45 | rspec-expectations (~> 3.10.0) 46 | rspec-mocks (~> 3.10.0) 47 | rspec-core (3.10.1) 48 | rspec-support (~> 3.10.0) 49 | rspec-expectations (3.10.2) 50 | diff-lcs (>= 1.2.0, < 2.0) 51 | rspec-support (~> 3.10.0) 52 | rspec-mocks (3.10.2) 53 | diff-lcs (>= 1.2.0, < 2.0) 54 | rspec-support (~> 3.10.0) 55 | rspec-support (3.10.3) 56 | tzinfo (2.0.6) 57 | concurrent-ruby (~> 1.0) 58 | 59 | PLATFORMS 60 | ruby 61 | 62 | DEPENDENCIES 63 | activerecord (~> 7.0.1) 64 | database_cleaner 65 | gemika (>= 0.8.1) 66 | has_defaults! 67 | pg (>= 1.3) 68 | pry-byebug (>= 3.10.1) 69 | rake 70 | rspec (~> 3.5) 71 | 72 | BUNDLED WITH 73 | 2.3.26 74 | -------------------------------------------------------------------------------- /Gemfile.7.1.pg: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | # Runtime dependencies 4 | gem 'activerecord', '~>7.1.5' 5 | gem 'pg', '>=1.3' 6 | 7 | # Development dependencies 8 | gem 'rake' 9 | gem 'database_cleaner' 10 | gem 'rspec', '~>3.5' 11 | gem 'gemika', '>=0.8.1' 12 | gem 'pry-byebug', '>=3.10.1' 13 | 14 | # Gem under test 15 | gem 'has_defaults', path: '.' 16 | -------------------------------------------------------------------------------- /Gemfile.7.1.pg.lock: -------------------------------------------------------------------------------- 1 | PATH 2 | remote: . 3 | specs: 4 | has_defaults (1.3.0) 5 | activerecord 6 | 7 | GEM 8 | remote: https://rubygems.org/ 9 | specs: 10 | activemodel (7.1.5) 11 | activesupport (= 7.1.5) 12 | activerecord (7.1.5) 13 | activemodel (= 7.1.5) 14 | activesupport (= 7.1.5) 15 | timeout (>= 0.4.0) 16 | activesupport (7.1.5) 17 | base64 18 | benchmark (>= 0.3) 19 | bigdecimal 20 | concurrent-ruby (~> 1.0, >= 1.0.2) 21 | connection_pool (>= 2.2.5) 22 | drb 23 | i18n (>= 1.6, < 2) 24 | logger (>= 1.4.2) 25 | minitest (>= 5.1) 26 | mutex_m 27 | securerandom (>= 0.3) 28 | tzinfo (~> 2.0) 29 | base64 (0.2.0) 30 | benchmark (0.4.0) 31 | bigdecimal (3.1.8) 32 | byebug (11.1.3) 33 | coderay (1.1.3) 34 | concurrent-ruby (1.3.4) 35 | connection_pool (2.4.1) 36 | database_cleaner (2.1.0) 37 | database_cleaner-active_record (>= 2, < 3) 38 | database_cleaner-active_record (2.2.0) 39 | activerecord (>= 5.a) 40 | database_cleaner-core (~> 2.0.0) 41 | database_cleaner-core (2.0.1) 42 | diff-lcs (1.5.1) 43 | drb (2.2.1) 44 | gemika (0.8.3) 45 | i18n (1.14.6) 46 | concurrent-ruby (~> 1.0) 47 | logger (1.6.1) 48 | method_source (1.1.0) 49 | minitest (5.25.2) 50 | mutex_m (0.3.0) 51 | pg (1.5.9) 52 | pry (0.14.2) 53 | coderay (~> 1.1) 54 | method_source (~> 1.0) 55 | pry-byebug (3.10.1) 56 | byebug (~> 11.0) 57 | pry (>= 0.13, < 0.15) 58 | rake (13.2.1) 59 | rspec (3.13.0) 60 | rspec-core (~> 3.13.0) 61 | rspec-expectations (~> 3.13.0) 62 | rspec-mocks (~> 3.13.0) 63 | rspec-core (3.13.2) 64 | rspec-support (~> 3.13.0) 65 | rspec-expectations (3.13.3) 66 | diff-lcs (>= 1.2.0, < 2.0) 67 | rspec-support (~> 3.13.0) 68 | rspec-mocks (3.13.2) 69 | diff-lcs (>= 1.2.0, < 2.0) 70 | rspec-support (~> 3.13.0) 71 | rspec-support (3.13.1) 72 | securerandom (0.3.2) 73 | timeout (0.4.2) 74 | tzinfo (2.0.6) 75 | concurrent-ruby (~> 1.0) 76 | 77 | PLATFORMS 78 | ruby 79 | 80 | DEPENDENCIES 81 | activerecord (~> 7.1.5) 82 | database_cleaner 83 | gemika (>= 0.8.1) 84 | has_defaults! 85 | pg (>= 1.3) 86 | pry-byebug (>= 3.10.1) 87 | rake 88 | rspec (~> 3.5) 89 | 90 | BUNDLED WITH 91 | 2.3.26 92 | -------------------------------------------------------------------------------- /Gemfile.7.2.pg: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | # Runtime dependencies 4 | gem 'activerecord', '~>7.2.2' 5 | gem 'pg', '>=1.3' 6 | 7 | # Development dependencies 8 | gem 'rake' 9 | gem 'database_cleaner' 10 | gem 'rspec', '~>3.5' 11 | gem 'gemika', '>=0.8.1' 12 | gem 'pry-byebug', '>=3.10.1' 13 | 14 | # Gem under test 15 | gem 'has_defaults', path: '.' 16 | -------------------------------------------------------------------------------- /Gemfile.7.2.pg.lock: -------------------------------------------------------------------------------- 1 | PATH 2 | remote: . 3 | specs: 4 | has_defaults (1.3.0) 5 | activerecord 6 | 7 | GEM 8 | remote: https://rubygems.org/ 9 | specs: 10 | activemodel (7.2.2) 11 | activesupport (= 7.2.2) 12 | activerecord (7.2.2) 13 | activemodel (= 7.2.2) 14 | activesupport (= 7.2.2) 15 | timeout (>= 0.4.0) 16 | activesupport (7.2.2) 17 | base64 18 | benchmark (>= 0.3) 19 | bigdecimal 20 | concurrent-ruby (~> 1.0, >= 1.3.1) 21 | connection_pool (>= 2.2.5) 22 | drb 23 | i18n (>= 1.6, < 2) 24 | logger (>= 1.4.2) 25 | minitest (>= 5.1) 26 | securerandom (>= 0.3) 27 | tzinfo (~> 2.0, >= 2.0.5) 28 | base64 (0.2.0) 29 | benchmark (0.4.0) 30 | bigdecimal (3.1.8) 31 | byebug (11.1.3) 32 | coderay (1.1.3) 33 | concurrent-ruby (1.3.4) 34 | connection_pool (2.4.1) 35 | database_cleaner (2.1.0) 36 | database_cleaner-active_record (>= 2, < 3) 37 | database_cleaner-active_record (2.2.0) 38 | activerecord (>= 5.a) 39 | database_cleaner-core (~> 2.0.0) 40 | database_cleaner-core (2.0.1) 41 | diff-lcs (1.5.1) 42 | drb (2.2.1) 43 | gemika (0.8.3) 44 | i18n (1.14.6) 45 | concurrent-ruby (~> 1.0) 46 | logger (1.6.1) 47 | method_source (1.1.0) 48 | minitest (5.25.2) 49 | pg (1.5.9) 50 | pry (0.14.2) 51 | coderay (~> 1.1) 52 | method_source (~> 1.0) 53 | pry-byebug (3.10.1) 54 | byebug (~> 11.0) 55 | pry (>= 0.13, < 0.15) 56 | rake (13.2.1) 57 | rspec (3.13.0) 58 | rspec-core (~> 3.13.0) 59 | rspec-expectations (~> 3.13.0) 60 | rspec-mocks (~> 3.13.0) 61 | rspec-core (3.13.2) 62 | rspec-support (~> 3.13.0) 63 | rspec-expectations (3.13.3) 64 | diff-lcs (>= 1.2.0, < 2.0) 65 | rspec-support (~> 3.13.0) 66 | rspec-mocks (3.13.2) 67 | diff-lcs (>= 1.2.0, < 2.0) 68 | rspec-support (~> 3.13.0) 69 | rspec-support (3.13.1) 70 | securerandom (0.3.2) 71 | timeout (0.4.2) 72 | tzinfo (2.0.6) 73 | concurrent-ruby (~> 1.0) 74 | 75 | PLATFORMS 76 | ruby 77 | 78 | DEPENDENCIES 79 | activerecord (~> 7.2.2) 80 | database_cleaner 81 | gemika (>= 0.8.1) 82 | has_defaults! 83 | pg (>= 1.3) 84 | pry-byebug (>= 3.10.1) 85 | rake 86 | rspec (~> 3.5) 87 | 88 | BUNDLED WITH 89 | 2.5.23 90 | -------------------------------------------------------------------------------- /Gemfile.8.0.pg: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | # Runtime dependencies 4 | gem 'activerecord', '~>8.0.0' 5 | gem 'pg', '>=1.3' 6 | 7 | # Development dependencies 8 | gem 'rake' 9 | gem 'database_cleaner' 10 | gem 'rspec', '~>3.5' 11 | gem 'gemika', '>=0.8.1' 12 | gem 'pry-byebug', '>=3.10.1' 13 | 14 | # Gem under test 15 | gem 'has_defaults', path: '.' 16 | -------------------------------------------------------------------------------- /Gemfile.8.0.pg.lock: -------------------------------------------------------------------------------- 1 | PATH 2 | remote: . 3 | specs: 4 | has_defaults (1.3.0) 5 | activerecord 6 | 7 | GEM 8 | remote: https://rubygems.org/ 9 | specs: 10 | activemodel (8.0.1) 11 | activesupport (= 8.0.1) 12 | activerecord (8.0.1) 13 | activemodel (= 8.0.1) 14 | activesupport (= 8.0.1) 15 | timeout (>= 0.4.0) 16 | activesupport (8.0.1) 17 | base64 18 | benchmark (>= 0.3) 19 | bigdecimal 20 | concurrent-ruby (~> 1.0, >= 1.3.1) 21 | connection_pool (>= 2.2.5) 22 | drb 23 | i18n (>= 1.6, < 2) 24 | logger (>= 1.4.2) 25 | minitest (>= 5.1) 26 | securerandom (>= 0.3) 27 | tzinfo (~> 2.0, >= 2.0.5) 28 | uri (>= 0.13.1) 29 | base64 (0.2.0) 30 | benchmark (0.4.0) 31 | bigdecimal (3.1.9) 32 | byebug (11.1.3) 33 | coderay (1.1.3) 34 | concurrent-ruby (1.3.5) 35 | connection_pool (2.5.0) 36 | database_cleaner (2.1.0) 37 | database_cleaner-active_record (>= 2, < 3) 38 | database_cleaner-active_record (2.2.0) 39 | activerecord (>= 5.a) 40 | database_cleaner-core (~> 2.0.0) 41 | database_cleaner-core (2.0.1) 42 | diff-lcs (1.5.1) 43 | drb (2.2.1) 44 | gemika (0.8.4) 45 | i18n (1.14.6) 46 | concurrent-ruby (~> 1.0) 47 | logger (1.6.5) 48 | method_source (1.1.0) 49 | minitest (5.25.4) 50 | pg (1.5.9) 51 | pry (0.14.2) 52 | coderay (~> 1.1) 53 | method_source (~> 1.0) 54 | pry-byebug (3.10.1) 55 | byebug (~> 11.0) 56 | pry (>= 0.13, < 0.15) 57 | rake (13.2.1) 58 | rspec (3.13.0) 59 | rspec-core (~> 3.13.0) 60 | rspec-expectations (~> 3.13.0) 61 | rspec-mocks (~> 3.13.0) 62 | rspec-core (3.13.2) 63 | rspec-support (~> 3.13.0) 64 | rspec-expectations (3.13.3) 65 | diff-lcs (>= 1.2.0, < 2.0) 66 | rspec-support (~> 3.13.0) 67 | rspec-mocks (3.13.2) 68 | diff-lcs (>= 1.2.0, < 2.0) 69 | rspec-support (~> 3.13.0) 70 | rspec-support (3.13.2) 71 | securerandom (0.4.1) 72 | timeout (0.4.3) 73 | tzinfo (2.0.6) 74 | concurrent-ruby (~> 1.0) 75 | uri (1.0.2) 76 | 77 | PLATFORMS 78 | x86_64-linux 79 | 80 | DEPENDENCIES 81 | activerecord (~> 8.0.0) 82 | database_cleaner 83 | gemika (>= 0.8.1) 84 | has_defaults! 85 | pg (>= 1.3) 86 | pry-byebug (>= 3.10.1) 87 | rake 88 | rspec (~> 3.5) 89 | 90 | BUNDLED WITH 91 | 2.4.7 92 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | Gemfile.7.0.pg.lock -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2008-2016 Nando Vieira, with subsequent changes by makandra GmbH 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # has_defaults [![Build Status](https://travis-ci.org/makandra/has_defaults.svg?branch=master)](https://travis-ci.org/makandra/has_defaults) 2 | 3 | Default values for ActiveRecord models. 4 | 5 | ## Installation 6 | 7 | In your `Gemfile` 8 | 9 | ```rb 10 | gem 'has_defaults' 11 | ``` 12 | 13 | Now run 14 | 15 | ```sh 16 | bundle install 17 | ``` 18 | 19 | ## Usage 20 | 21 | Add the method call `has_defaults` to your model. 22 | 23 | ```rb 24 | class Page < ActiveRecord::Base 25 | has_defaults :title => "New page", :body => "Put your text here" 26 | end 27 | ``` 28 | 29 | Attributes will be set only if it's a new record and the attribute is blank. 30 | 31 | Retrieve the default attribute with the `default_for` instance method: 32 | 33 | ```rb 34 | @page.default_for(:title) 35 | ``` 36 | 37 | You can pass Proc as attribute: 38 | 39 | ```rb 40 | has_defaults :expires_at => proc { Time.now } 41 | ``` 42 | 43 | You can override the default attributes as follow: 44 | 45 | ```rb 46 | Page.has_defaults_options = {:title => "Here's your new page", :body => "Write your page text"} 47 | ``` 48 | 49 | ## Development 50 | 51 | There are tests in `spec`. We only accept PRs with tests. To run tests: 52 | 53 | - Install Ruby 2.7.4 54 | - Create a local test database `has_defaults_test` in both MySQL and PostgreSQL 55 | - Copy `spec/support/database.sample.yml` to `spec/support/database.yml` and enter your local credentials for the test databases 56 | - Install development dependencies using `bundle install` 57 | - Run tests using `bundle exec rspec` 58 | 59 | We recommend to test large changes against multiple versions of Ruby and multiple dependency sets. We provide some rake tasks to help with this: 60 | 61 | - Install development dependencies using `rake matrix:install` 62 | - Run tests using `rake matrix:spec` 63 | 64 | Note that we have configured Github Actions to automatically run tests in all supported Ruby versions and dependency sets after each push. We will only merge pull requests with successful test runs. 65 | 66 | 67 | ## Credits 68 | 69 | * Original version by Nando Vieira () 70 | * Patches in this fork by makandra () 71 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require 'rake' 2 | require 'bundler/gem_tasks' 3 | begin 4 | require 'gemika/tasks' 5 | rescue LoadError 6 | puts 'Run `gem install gemika` for additional tasks' 7 | end 8 | 9 | task :default => 'matrix:spec' 10 | -------------------------------------------------------------------------------- /has_defaults.gemspec: -------------------------------------------------------------------------------- 1 | lib = File.expand_path('lib', __dir__) 2 | $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) 3 | require "has_defaults/version" 4 | 5 | Gem::Specification.new do |spec| 6 | spec.name = 'has_defaults' 7 | spec.version = HasDefaults::VERSION 8 | spec.required_ruby_version = '>= 2.3.0' 9 | spec.authors = ['Henning Koch'] 10 | spec.email = ['henning.koch@makandra.de'] 11 | 12 | spec.summary = 'Default values for ActiveRecord models' 13 | spec.description = 'Default values for ActiveRecord models' 14 | spec.homepage = 'https://github.com/makandra/has_defaults' 15 | spec.license = 'MIT' 16 | spec.metadata = { 'rubygems_mfa_required' => 'true' } 17 | 18 | # Specify which files should be added to the gem when it is released. 19 | # The `git ls-files -z` loads the files in the RubyGem that have been added into git. 20 | spec.files = Dir.chdir(File.expand_path(__dir__)) do 21 | `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) } 22 | end 23 | spec.bindir = 'exe' 24 | spec.executables = spec.files.grep(%r(^exe/)) { |f| File.basename(f) } 25 | spec.require_paths = ['lib'] 26 | 27 | spec.add_dependency('activerecord') 28 | 29 | # Development dependencies are defined in the Gemfile (therefore no `spec.add_development_dependency` directives) 30 | end 31 | -------------------------------------------------------------------------------- /lib/has_defaults.rb: -------------------------------------------------------------------------------- 1 | require 'active_record' 2 | require 'has_defaults/active_record_ext' 3 | -------------------------------------------------------------------------------- /lib/has_defaults/active_record_ext.rb: -------------------------------------------------------------------------------- 1 | module HasDefaults 2 | 3 | class Error < StandardError; end 4 | 5 | module ActiveRecordExt 6 | 7 | module ClassMethods 8 | 9 | def has_defaults(attrs) 10 | raise Error, "Hash expected; #{attrs.class} given." unless attrs.is_a?(Hash) 11 | 12 | include InstanceMethods 13 | 14 | # Check if our parent class had default options, whose accessor we inherited. 15 | # In this case we clone the default options as to not modify the options of our parent. 16 | if respond_to?(:has_defaults_options) 17 | self.has_defaults_options = has_defaults_options.dup 18 | else 19 | # Rails 3 and 2 have different copy-and-write accessor generators. 20 | if respond_to?(:class_attribute) 21 | class_attribute :has_defaults_options 22 | else 23 | class_inheritable_hash :has_defaults_options 24 | end 25 | # We only register the callback if we haven't registered it before, 26 | # since in this branch we didn't inherit #has_defaults_options 27 | after_initialize :set_default_attributes 28 | end 29 | 30 | self.has_defaults_options ||= {} 31 | self.has_defaults_options.merge!(attrs) 32 | end 33 | 34 | end 35 | 36 | module InstanceMethods 37 | 38 | def default_for(name) 39 | raw_value = self.class.has_defaults_options[name.to_sym] 40 | evaluate_raw_default_value(raw_value) 41 | end 42 | 43 | private 44 | 45 | def set_default_attributes 46 | if new_record? 47 | self.class.has_defaults_options.each do |name, raw_value| 48 | if send(name).nil? 49 | value = evaluate_raw_default_value(raw_value) 50 | send("#{name}=", value) 51 | end 52 | end 53 | end 54 | end 55 | 56 | def evaluate_raw_default_value(raw_value) 57 | value = raw_value 58 | if value.respond_to?(:call) 59 | value = instance_exec(&value) 60 | end 61 | value 62 | end 63 | 64 | end 65 | 66 | end 67 | end 68 | 69 | ActiveSupport.on_load(:active_record) do 70 | extend(HasDefaults::ActiveRecordExt::ClassMethods) 71 | end 72 | -------------------------------------------------------------------------------- /lib/has_defaults/version.rb: -------------------------------------------------------------------------------- 1 | module HasDefaults 2 | 3 | VERSION = '1.3.0' 4 | 5 | end 6 | -------------------------------------------------------------------------------- /spec/has_defaults/active_record_ext_spec.rb: -------------------------------------------------------------------------------- 1 | require "spec_helper" 2 | 3 | describe HasDefaults::ActiveRecordExt do 4 | 5 | context "given a model with defaults" do 6 | 7 | describe 'initialization' do 8 | 9 | it "should set defaults" do 10 | new_donut = Donut.new 11 | new_donut.flavor.should == "cream" 12 | new_donut.name.should == "Cream" 13 | end 14 | 15 | it "should use setters methods to set the defaults" do 16 | new_donut = Donut.new 17 | new_donut.instance_variable_get('@flavor_setter_called').should == true 18 | end 19 | 20 | it "should call procs in the model context when given as defaults" do 21 | new_donut = Donut.new 22 | new_donut.weight.should == 'a lot' 23 | end 24 | 25 | it "should merge multiple has_defaults directives" do 26 | new_donut = Donut.new 27 | new_donut.flavor.should == "cream" 28 | new_donut.maker.should == "Dunkin Donuts" 29 | end 30 | 31 | it 'should not assign attributes multiple times when there are multiple has_defaults directives (bugfix)' do 32 | Donut.should_receive(:global_health_benefits).once 33 | Donut.new 34 | end 35 | 36 | it "should set defaults only if attributes are nil" do 37 | donut = Donut.new(:flavor => 'vanilla') 38 | donut.flavor.should == "vanilla" 39 | end 40 | 41 | it "should not set a default on an attribute that is set to an empty string" do 42 | donut = Donut.new(:flavor => '') 43 | donut.flavor.should == '' 44 | end 45 | 46 | it "should use getters methods to check if an attribute is nil" do 47 | new_donut = Donut.new 48 | new_donut.instance_variable_get('@flavor_getter_called').should == true 49 | end 50 | 51 | it "should return default value for an attribute" do 52 | Donut.new.default_for(:flavor).should == "cream" 53 | end 54 | 55 | it "should not set defaults when loading a saved record" do 56 | Donut.create(:flavor => "vanilla") 57 | Donut.first.flavor.should == "vanilla" 58 | end 59 | 60 | it "should define #after_initialize in Rails 2, but not Rails 3 (this method must be defined so after_initialize callbacks run)" do 61 | donut = Donut.new 62 | if ActiveRecord::VERSION::MAJOR < 3 63 | donut.should respond_to(:after_initialize) 64 | else 65 | donut.should_not respond_to(:after_initialize) 66 | end 67 | end 68 | 69 | it "should not redefine defaults in its superclass" do 70 | pastry = Pastry.new 71 | pastry.maker.should == 'Mom' 72 | pastry.default_for(:maker).should == 'Mom' 73 | end 74 | 75 | it "should respect defaults from its superclass" do 76 | donut = Donut.create 77 | donut.main_ingredient.should == 'flour' 78 | donut.maker.should_not == 'Mom' 79 | end 80 | 81 | end 82 | 83 | describe '#default_for' do 84 | 85 | it "should return the default value for the given attribute" do 86 | Donut.new.default_for(:flavor).should == 'cream' 87 | end 88 | 89 | it 'should evaluate the default value if it is a lambda' do 90 | Donut.new.default_for(:weight).should == 'a lot' 91 | end 92 | 93 | end 94 | 95 | end 96 | 97 | context "given a model without defaults" do 98 | 99 | it "should not define #after_initialize so initialization remains fast" do 100 | ModelWithoutDefaults.new.should_not respond_to(:after_initialize) 101 | end 102 | 103 | end 104 | 105 | end 106 | -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | $: << File.join(File.dirname(__FILE__), "/../../lib" ) 2 | 3 | require 'has_defaults' 4 | require 'gemika' 5 | require 'pry' 6 | 7 | if ActiveRecord::VERSION::MAJOR >= 7 8 | ActiveRecord.default_timezone = :local 9 | else 10 | ActiveRecord::Base.default_timezone = :local 11 | end 12 | 13 | Dir["#{File.dirname(__FILE__)}/support/*.rb"].sort.each {|f| require f} 14 | Dir["#{File.dirname(__FILE__)}/shared_examples/*.rb"].sort.each {|f| require f} 15 | 16 | Gemika::RSpec.configure_clean_database_before_example 17 | Gemika::RSpec.configure_should_syntax 18 | -------------------------------------------------------------------------------- /spec/support/database.github.yml: -------------------------------------------------------------------------------- 1 | mysql: 2 | database: test 3 | username: root 4 | password: password 5 | host: 127.0.0.1 6 | port: 3306 7 | 8 | postgresql: 9 | database: test 10 | host: localhost 11 | username: postgres 12 | password: postgres 13 | port: 5432 14 | -------------------------------------------------------------------------------- /spec/support/database.rb: -------------------------------------------------------------------------------- 1 | Gemika::Database.new.rewrite_schema! do 2 | 3 | create_table :pastries do |t| 4 | t.string :type 5 | t.string :flavor 6 | t.string :name 7 | t.string :maker 8 | t.string :weight 9 | t.string :main_ingredient 10 | t.string :health_benefits 11 | end 12 | 13 | create_table :model_without_defaults do |t| 14 | end 15 | 16 | end 17 | -------------------------------------------------------------------------------- /spec/support/database.sample.yml: -------------------------------------------------------------------------------- 1 | mysql: 2 | database: has_defaults_test 3 | host: localhost 4 | username: root 5 | password: secret 6 | 7 | postgresql: 8 | database: has_defaults_test 9 | user: 10 | password: 11 | -------------------------------------------------------------------------------- /spec/support/database.travis.yml: -------------------------------------------------------------------------------- 1 | mysql: 2 | database: has_defaults_test 3 | username: travis 4 | password: 5 | 6 | postgresql: 7 | database: has_defaults_test 8 | user: postgres 9 | password: 10 | -------------------------------------------------------------------------------- /spec/support/models.rb: -------------------------------------------------------------------------------- 1 | class Pastry < ActiveRecord::Base 2 | 3 | has_defaults :main_ingredient => "flour", :maker => "Mom" 4 | 5 | end 6 | 7 | 8 | class Donut < Pastry 9 | 10 | has_defaults :flavor => "cream", :name => "Cream" 11 | has_defaults :maker => lambda { "Dunkin Donuts" } 12 | has_defaults :weight => lambda { weigh } 13 | has_defaults :health_benefits => lambda { self.class.global_health_benefits } 14 | 15 | def flavor 16 | @flavor_getter_called = true 17 | read_attribute(:flavor) 18 | end 19 | 20 | def flavor=(value) 21 | @flavor_setter_called = true 22 | write_attribute(:flavor, value) 23 | end 24 | 25 | def weigh 26 | "a lot" 27 | end 28 | 29 | def self.global_health_benefits 30 | 'none' 31 | end 32 | 33 | end 34 | 35 | 36 | class ModelWithoutDefaults < ActiveRecord::Base 37 | end 38 | --------------------------------------------------------------------------------