diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9f4f04420..027dfd21e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -31,6 +31,7 @@ jobs: - 2.7.3 - 2.6.7 appraisal: + - rails_6_1 - rails_6_0 - rails_5_2 adapter: diff --git a/Appraisals b/Appraisals index b9f991cc9..106d7e4f9 100644 --- a/Appraisals +++ b/Appraisals @@ -69,3 +69,29 @@ appraise 'rails_6_0' do gem 'pg', '>= 0.18', '< 2.0' gem 'sqlite3', '~> 1.4' end + +appraise 'rails_6_1' do + instance_eval(&shared_dependencies) + instance_eval(&controller_test_dependency) + + gem 'rails', '6.1.3.2' + gem 'puma', '~> 5.0' + gem 'bootsnap', '>= 1.4.2', require: false + gem 'sass-rails', '>= 6' + gem 'turbolinks', '~> 5' + gem 'jbuilder', '~> 2.7' + gem 'bcrypt', '~> 3.1.7' + gem 'capybara', '>= 2.15' + gem 'listen', '>= 3.0.5', '< 3.6' + gem 'rack-mini-profiler', '~> 2.0.0' + gem 'spring-watcher-listen', '~> 2.0.0' + gem 'selenium-webdriver' + gem 'webdrivers' + + # Other dependencies + gem 'actiontext', '~> 6.1.3.2' + + # Database adapters + gem 'pg', '>= 0.18', '< 2.0' + gem 'sqlite3', '~> 1.4' +end diff --git a/gemfiles/rails_5_2.gemfile.lock b/gemfiles/rails_5_2.gemfile.lock index 59e517a28..7c1976f66 100644 --- a/gemfiles/rails_5_2.gemfile.lock +++ b/gemfiles/rails_5_2.gemfile.lock @@ -93,11 +93,11 @@ GEM marcel (1.0.1) method_source (1.0.0) mini_mime (1.1.0) - mini_portile2 (2.5.1) + mini_portile2 (2.5.3) minitest (5.14.4) msgpack (1.4.2) nio4r (2.5.7) - nokogiri (1.11.3) + nokogiri (1.11.6) mini_portile2 (~> 2.5.0) racc (~> 1.4) parallel (1.20.1) @@ -165,7 +165,7 @@ GEM rspec-mocks (3.10.2) diff-lcs (>= 1.2.0, < 2.0) rspec-support (~> 3.10.0) - rspec-rails (4.0.2) + rspec-rails (4.1.2) actionpack (>= 4.2) activesupport (>= 4.2) railties (>= 4.2) diff --git a/gemfiles/rails_6_0.gemfile.lock b/gemfiles/rails_6_0.gemfile.lock index 8c7335d33..e1d9e49f2 100644 --- a/gemfiles/rails_6_0.gemfile.lock +++ b/gemfiles/rails_6_0.gemfile.lock @@ -101,11 +101,11 @@ GEM marcel (1.0.1) method_source (1.0.0) mini_mime (1.1.0) - mini_portile2 (2.5.1) + mini_portile2 (2.5.3) minitest (5.14.4) msgpack (1.4.2) nio4r (2.5.7) - nokogiri (1.11.3) + nokogiri (1.11.6) mini_portile2 (~> 2.5.0) racc (~> 1.4) parallel (1.20.1) @@ -176,7 +176,7 @@ GEM rspec-mocks (3.10.2) diff-lcs (>= 1.2.0, < 2.0) rspec-support (~> 3.10.0) - rspec-rails (4.0.2) + rspec-rails (4.1.2) actionpack (>= 4.2) activesupport (>= 4.2) railties (>= 4.2) diff --git a/gemfiles/rails_6_1.gemfile b/gemfiles/rails_6_1.gemfile new file mode 100644 index 000000000..4ac94b3f0 --- /dev/null +++ b/gemfiles/rails_6_1.gemfile @@ -0,0 +1,40 @@ +# This file was generated by Appraisal + +source "https://rubygems.org" + +gem "appraisal", "2.2.0" +gem "bundler", "~> 1.1" +gem "pry" +gem "pry-byebug" +gem "rake", "13.0.1" +gem "rspec", "~> 3.9" +gem "rubocop", require: false +gem "rubocop-packaging", require: false +gem "rubocop-rails", require: false +gem "warnings_logger" +gem "zeus", require: false +gem "fssm" +gem "redcarpet" +gem "rouge" +gem "yard" +gem "spring" +gem "spring-commands-rspec" +gem "rspec-rails", "~> 4.0" +gem "shoulda-context", "~> 1.2.0" +gem "rails-controller-testing", ">= 1.0.1" +gem "rails", "6.1.3.2" +gem "puma", "~> 5.0" +gem "bootsnap", ">= 1.4.2", require: false +gem "sass-rails", ">= 6" +gem "turbolinks", "~> 5" +gem "jbuilder", "~> 2.7" +gem "bcrypt", "~> 3.1.7" +gem "capybara", ">= 2.15" +gem "listen", ">= 3.0.5", "< 3.6" +gem "rack-mini-profiler", "~> 2.0.0" +gem "spring-watcher-listen", "~> 2.0.0" +gem "selenium-webdriver" +gem "webdrivers" +gem "actiontext", "~> 6.1.3.2" +gem "pg", ">= 0.18", "< 2.0" +gem "sqlite3", "~> 1.4" diff --git a/gemfiles/rails_6_1.gemfile.lock b/gemfiles/rails_6_1.gemfile.lock new file mode 100644 index 000000000..8600fadd7 --- /dev/null +++ b/gemfiles/rails_6_1.gemfile.lock @@ -0,0 +1,306 @@ +GEM + remote: https://rubygems.org/ + specs: + actioncable (6.1.3.2) + actionpack (= 6.1.3.2) + activesupport (= 6.1.3.2) + nio4r (~> 2.0) + websocket-driver (>= 0.6.1) + actionmailbox (6.1.3.2) + actionpack (= 6.1.3.2) + activejob (= 6.1.3.2) + activerecord (= 6.1.3.2) + activestorage (= 6.1.3.2) + activesupport (= 6.1.3.2) + mail (>= 2.7.1) + actionmailer (6.1.3.2) + actionpack (= 6.1.3.2) + actionview (= 6.1.3.2) + activejob (= 6.1.3.2) + activesupport (= 6.1.3.2) + mail (~> 2.5, >= 2.5.4) + rails-dom-testing (~> 2.0) + actionpack (6.1.3.2) + actionview (= 6.1.3.2) + activesupport (= 6.1.3.2) + rack (~> 2.0, >= 2.0.9) + rack-test (>= 0.6.3) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.0, >= 1.2.0) + actiontext (6.1.3.2) + actionpack (= 6.1.3.2) + activerecord (= 6.1.3.2) + activestorage (= 6.1.3.2) + activesupport (= 6.1.3.2) + nokogiri (>= 1.8.5) + actionview (6.1.3.2) + activesupport (= 6.1.3.2) + builder (~> 3.1) + erubi (~> 1.4) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.1, >= 1.2.0) + activejob (6.1.3.2) + activesupport (= 6.1.3.2) + globalid (>= 0.3.6) + activemodel (6.1.3.2) + activesupport (= 6.1.3.2) + activerecord (6.1.3.2) + activemodel (= 6.1.3.2) + activesupport (= 6.1.3.2) + activestorage (6.1.3.2) + actionpack (= 6.1.3.2) + activejob (= 6.1.3.2) + activerecord (= 6.1.3.2) + activesupport (= 6.1.3.2) + marcel (~> 1.0.0) + mini_mime (~> 1.0.2) + activesupport (6.1.3.2) + concurrent-ruby (~> 1.0, >= 1.0.2) + i18n (>= 1.6, < 2) + minitest (>= 5.1) + tzinfo (~> 2.0) + zeitwerk (~> 2.3) + addressable (2.7.0) + public_suffix (>= 2.0.2, < 5.0) + appraisal (2.2.0) + bundler + rake + thor (>= 0.14.0) + ast (2.4.2) + bcrypt (3.1.16) + bootsnap (1.7.2) + msgpack (~> 1.0) + builder (3.2.4) + byebug (11.1.3) + capybara (3.35.3) + addressable + mini_mime (>= 0.1.3) + nokogiri (~> 1.8) + rack (>= 1.6.0) + rack-test (>= 0.6.3) + regexp_parser (>= 1.5, < 3.0) + xpath (~> 3.2) + childprocess (3.0.0) + coderay (1.1.3) + concurrent-ruby (1.1.8) + crass (1.0.6) + diff-lcs (1.4.4) + erubi (1.10.0) + ffi (1.15.0) + fssm (0.2.10) + globalid (0.4.2) + activesupport (>= 4.2.0) + i18n (1.8.10) + concurrent-ruby (~> 1.0) + jbuilder (2.11.2) + activesupport (>= 5.0.0) + listen (3.5.1) + rb-fsevent (~> 0.10, >= 0.10.3) + rb-inotify (~> 0.9, >= 0.9.10) + loofah (2.9.1) + crass (~> 1.0.2) + nokogiri (>= 1.5.9) + mail (2.7.1) + mini_mime (>= 0.1.1) + marcel (1.0.1) + method_source (1.0.0) + mini_mime (1.0.3) + mini_portile2 (2.5.3) + minitest (5.14.4) + msgpack (1.4.2) + nio4r (2.5.7) + nokogiri (1.11.6) + mini_portile2 (~> 2.5.0) + racc (~> 1.4) + parallel (1.20.1) + parser (3.0.0.0) + ast (~> 2.4.1) + pg (1.2.3) + pry (0.14.0) + coderay (~> 1.1) + method_source (~> 1.0) + pry-byebug (3.8.0) + byebug (~> 11.0) + pry (~> 0.10) + public_suffix (4.0.6) + puma (5.2.2) + nio4r (~> 2.0) + racc (1.5.2) + rack (2.2.3) + rack-mini-profiler (2.0.4) + rack (>= 1.2.0) + rack-test (1.1.0) + rack (>= 1.0, < 3) + rails (6.1.3.2) + actioncable (= 6.1.3.2) + actionmailbox (= 6.1.3.2) + actionmailer (= 6.1.3.2) + actionpack (= 6.1.3.2) + actiontext (= 6.1.3.2) + actionview (= 6.1.3.2) + activejob (= 6.1.3.2) + activemodel (= 6.1.3.2) + activerecord (= 6.1.3.2) + activestorage (= 6.1.3.2) + activesupport (= 6.1.3.2) + bundler (>= 1.15.0) + railties (= 6.1.3.2) + sprockets-rails (>= 2.0.0) + rails-controller-testing (1.0.5) + actionpack (>= 5.0.1.rc1) + actionview (>= 5.0.1.rc1) + activesupport (>= 5.0.1.rc1) + rails-dom-testing (2.0.3) + activesupport (>= 4.2.0) + nokogiri (>= 1.6) + rails-html-sanitizer (1.3.0) + loofah (~> 2.3) + railties (6.1.3.2) + actionpack (= 6.1.3.2) + activesupport (= 6.1.3.2) + method_source + rake (>= 0.8.7) + thor (~> 1.0) + rainbow (3.0.0) + rake (13.0.1) + rb-fsevent (0.10.4) + rb-inotify (0.10.1) + ffi (~> 1.0) + redcarpet (3.5.1) + regexp_parser (2.0.3) + rexml (3.2.4) + rouge (3.26.0) + rspec (3.9.0) + rspec-core (~> 3.9.0) + rspec-expectations (~> 3.9.0) + rspec-mocks (~> 3.9.0) + rspec-core (3.9.3) + rspec-support (~> 3.9.3) + rspec-expectations (3.9.4) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.9.0) + rspec-mocks (3.9.1) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.9.0) + rspec-rails (4.0.1) + actionpack (>= 4.2) + activesupport (>= 4.2) + railties (>= 4.2) + rspec-core (~> 3.9) + rspec-expectations (~> 3.9) + rspec-mocks (~> 3.9) + rspec-support (~> 3.9) + rspec-support (3.9.4) + rubocop (1.10.0) + parallel (~> 1.10) + parser (>= 3.0.0.0) + rainbow (>= 2.2.2, < 4.0) + regexp_parser (>= 1.8, < 3.0) + rexml + rubocop-ast (>= 1.2.0, < 2.0) + ruby-progressbar (~> 1.7) + unicode-display_width (>= 1.4.0, < 3.0) + rubocop-ast (1.4.1) + parser (>= 2.7.1.5) + rubocop-packaging (0.5.1) + rubocop (>= 0.89, < 2.0) + rubocop-rails (2.9.1) + activesupport (>= 4.2.0) + rack (>= 1.1) + rubocop (>= 0.90.0, < 2.0) + ruby-progressbar (1.11.0) + rubyzip (2.3.0) + sass-rails (6.0.0) + sassc-rails (~> 2.1, >= 2.1.1) + sassc (2.4.0) + ffi (~> 1.9) + sassc-rails (2.1.2) + railties (>= 4.0.0) + sassc (>= 2.0) + sprockets (> 3.0) + sprockets-rails + tilt + selenium-webdriver (3.142.7) + childprocess (>= 0.5, < 4.0) + rubyzip (>= 1.2.2) + shoulda-context (1.2.2) + spring (2.1.1) + spring-commands-rspec (1.0.4) + spring (>= 0.9.1) + spring-watcher-listen (2.0.1) + listen (>= 2.7, < 4.0) + spring (>= 1.2, < 3.0) + sprockets (4.0.2) + concurrent-ruby (~> 1.0) + rack (> 1, < 3) + sprockets-rails (3.2.2) + actionpack (>= 4.0) + activesupport (>= 4.0) + sprockets (>= 3.0.0) + sqlite3 (1.4.2) + thor (1.1.0) + tilt (2.0.10) + turbolinks (5.2.1) + turbolinks-source (~> 5.2) + turbolinks-source (5.2.0) + tzinfo (2.0.4) + concurrent-ruby (~> 1.0) + unicode-display_width (2.0.0) + warnings_logger (0.1.1) + webdrivers (4.5.0) + nokogiri (~> 1.6) + rubyzip (>= 1.3.0) + selenium-webdriver (>= 3.0, < 4.0) + websocket-driver (0.7.3) + websocket-extensions (>= 0.1.0) + websocket-extensions (0.1.5) + xpath (3.2.0) + nokogiri (~> 1.8) + yard (0.9.26) + zeitwerk (2.4.2) + zeus (0.15.14) + method_source (>= 0.6.7) + +PLATFORMS + ruby + +DEPENDENCIES + actiontext (~> 6.1.3.2) + appraisal (= 2.2.0) + bcrypt (~> 3.1.7) + bootsnap (>= 1.4.2) + bundler (~> 1.1) + capybara (>= 2.15) + fssm + jbuilder (~> 2.7) + listen (>= 3.0.5, < 3.6) + pg (>= 0.18, < 2.0) + pry + pry-byebug + puma (~> 5.0) + rack-mini-profiler (~> 2.0.0) + rails (= 6.1.3.2) + rails-controller-testing (>= 1.0.1) + rake (= 13.0.1) + redcarpet + rouge + rspec (~> 3.9) + rspec-rails (~> 4.0) + rubocop + rubocop-packaging + rubocop-rails + sass-rails (>= 6) + selenium-webdriver + shoulda-context (~> 1.2.0) + spring + spring-commands-rspec + spring-watcher-listen (~> 2.0.0) + sqlite3 (~> 1.4) + turbolinks (~> 5) + warnings_logger + webdrivers + yard + zeus + +BUNDLED WITH + 1.17.3 diff --git a/lib/shoulda/matchers/active_model/validator.rb b/lib/shoulda/matchers/active_model/validator.rb index 740732279..a319444d4 100644 --- a/lib/shoulda/matchers/active_model/validator.rb +++ b/lib/shoulda/matchers/active_model/validator.rb @@ -98,12 +98,7 @@ def perform_validation all_validation_errors = record.errors.dup - validation_error_messages = - if record.errors.respond_to?(:[]) - record.errors[attribute] - else - record.errors.on(attribute) - end + validation_error_messages = record.errors[attribute] { all_validation_errors: all_validation_errors, diff --git a/lib/shoulda/matchers/active_record/association_matcher.rb b/lib/shoulda/matchers/active_record/association_matcher.rb index 210b7f832..28e13d66e 100644 --- a/lib/shoulda/matchers/active_record/association_matcher.rb +++ b/lib/shoulda/matchers/active_record/association_matcher.rb @@ -1394,23 +1394,25 @@ def touch_correct? end def class_has_foreign_key?(klass) + @missing = validate_foreign_key(klass) + + @missing.nil? + end + + def validate_foreign_key(klass) if options.key?(:foreign_key) && !foreign_key_correct? - @missing = foreign_key_failure_message(klass, options[:foreign_key]) - false - elsif !has_column?(klass, foreign_key) - @missing = foreign_key_failure_message(klass, foreign_key) - false - else - true + foreign_key_failure_message(klass, options[:foreign_key]) + elsif !has_column?(klass, actual_foreign_key) + foreign_key_failure_message(klass, actual_foreign_key) end end def has_column?(klass, column) case column when Array - column.all? { |c| has_column?(klass, c) } + column.all? { |c| has_column?(klass, c.to_s) } else - column_names_for(klass).include?(column) + column_names_for(klass).include?(column.to_s) end end @@ -1442,19 +1444,15 @@ def primary_key_correct?(klass) end end - def foreign_key - key = if foreign_key_reflection - if foreign_key_reflection.respond_to?(:foreign_key) - foreign_key_reflection.foreign_key - else - foreign_key_reflection.primary_key_name - end - end - - if key.is_a?(Array) - key.map(&:to_s) + def actual_foreign_key + return unless foreign_key_reflection + + if foreign_key_reflection.options[:foreign_key] + foreign_key_reflection.options[:foreign_key] + elsif foreign_key_reflection.respond_to?(:foreign_key) + foreign_key_reflection.foreign_key else - key.to_s + foreign_key_reflection.primary_key_name end end diff --git a/spec/support/acceptance/helpers/rails_version_helpers.rb b/spec/support/acceptance/helpers/rails_version_helpers.rb index 02f207114..1cd24bd3a 100644 --- a/spec/support/acceptance/helpers/rails_version_helpers.rb +++ b/spec/support/acceptance/helpers/rails_version_helpers.rb @@ -7,5 +7,9 @@ module RailsVersionHelpers def rails_version bundle_version_of('rails') end + + def rails_gt_6_0? + rails_version > 6.0 + end end end diff --git a/spec/support/acceptance/helpers/step_helpers.rb b/spec/support/acceptance/helpers/step_helpers.rb index 502ab173b..fa972ecf4 100644 --- a/spec/support/acceptance/helpers/step_helpers.rb +++ b/spec/support/acceptance/helpers/step_helpers.rb @@ -118,6 +118,7 @@ def add_rspec_to_project def add_rspec_rails_to_project! add_gem 'rspec-rails', rspec_rails_version + run_command_within_bundle!('bundle install --binstubs') if rails_gt_6_0? run_command_within_bundle!('rails g rspec:install') remove_from_file '.rspec', '--warnings' end diff --git a/spec/unit/shoulda/matchers/active_model/helpers_spec.rb b/spec/unit/shoulda/matchers/active_model/helpers_spec.rb index 8246997c2..95c0fdf50 100644 --- a/spec/unit/shoulda/matchers/active_model/helpers_spec.rb +++ b/spec/unit/shoulda/matchers/active_model/helpers_spec.rb @@ -78,16 +78,6 @@ end end end - - context 'if ActiveModel::Errors#generate_message behavior has changed' do - it 'provides the right error message for validate_presence_of' do - stub_active_model_message_generation( - type: :blank, - message: 'Behavior has diverged.', - ) - assert_presence_validation_has_correct_message - end - end end def assert_presence_validation_has_correct_message @@ -150,16 +140,4 @@ def store_translations(options = { without: [] }) # rubocop:disable Metrics/Meth I18n.backend.store_translations(:en, translations) end - - def stub_active_model_message_generation(options = {}) - attribute = options.delete(:attribute) || :attr - message = options.delete(:message) - type = options.delete(:type) - - expect_any_instance_of(ActiveModel::Errors). - to receive(:generate_message). - with(attribute, type, {}). - at_least(1). - and_return(message) - end end diff --git a/spec/unit/shoulda/matchers/active_record/association_matcher_spec.rb b/spec/unit/shoulda/matchers/active_record/association_matcher_spec.rb index a5276ab9d..626728c42 100644 --- a/spec/unit/shoulda/matchers/active_record/association_matcher_spec.rb +++ b/spec/unit/shoulda/matchers/active_record/association_matcher_spec.rb @@ -885,8 +885,16 @@ def belonging_to_non_existent_class(model_name, assoc_name, options = {}) end it 'accepts an association with a valid :source option' do - expect(having_many_children(source: :user)). - to have_many(:children).source(:user) + define_model(:author) do + has_many :books + has_many :paperbacks, through: :books, source: :format, source_type: 'Paperback' + end + define_model(:book, format_id: :integer) do + belongs_to :format, polymorphic: true + end + define_model(:paperback) + + expect(Author.new).to have_many(:paperbacks).source(:format) end it 'rejects an association with a bad :source option' do @@ -1350,7 +1358,7 @@ def having_many_non_existent_class(model_name, assoc_name, options = {}) end expected_message = 'Expected Person to have a has_one association called detail ' \ - '(PersonDetail does not have a ["company_id", "person_detail_id"] foreign key.)' + '(PersonDetail does not have a [:company_id, :person_detail_id] foreign key.)' expect do have_one(:detail).class_name('PersonDetail'). diff --git a/spec/unit/shoulda/matchers/active_record/have_db_index_matcher_spec.rb b/spec/unit/shoulda/matchers/active_record/have_db_index_matcher_spec.rb index d7c90d44f..12a9229be 100644 --- a/spec/unit/shoulda/matchers/active_record/have_db_index_matcher_spec.rb +++ b/spec/unit/shoulda/matchers/active_record/have_db_index_matcher_spec.rb @@ -489,7 +489,7 @@ def record_with_index_on( columns, parent_class: parent_class, customize_table: -> (table) { - table.index(column_name_or_names, index_options) + table.index(column_name_or_names, **index_options) }, ) model.new