Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
119 changes: 118 additions & 1 deletion lib/shoulda/matchers/active_record/association_matcher.rb
Original file line number Diff line number Diff line change
Expand Up @@ -372,6 +372,25 @@ module ActiveRecord
# should belong_to(:organization).optional
# end
#
# ##### deprecated
#
# Use `deprecated` to assert that the `:deprecated` option was specified.
# (Enabled by default in Rails 8.1+).
#
# class Account < ActiveRecord::Base
# belongs_to :bank, deprecated: true
# end
#
# # RSpec
# RSpec.describe Account, type: :model do
# it { should belong_to(:bank).deprecated(true) }
# end
#
# # Minitest (Shoulda)
# class AccountTest < ActiveSupport::TestCase
# should belong_to(:bank).deprecated(true)
# end
#
Comment on lines +375 to +393
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's move this up before the line 375

# ... new doc
#
# @return [AssociationMatcher]

The same comment applies to the other doc comments.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch, thanks! Done in 2239770

# @return [AssociationMatcher]
#
def belong_to(name)
Expand Down Expand Up @@ -681,9 +700,27 @@ def belong_to(name)
# should have_delegated_type(:drivable).optional
# end
#
# ##### deprecated
#
# Use `deprecated` to assert that the association is not allowed to be nil.
# (Enabled by default in Rails 8.1+).
#
# class Vehicle < ActiveRecord::Base
# delegated_type :drivable, types: %w(Car Truck), deprecated: true
# end
#
# # RSpec
# describe Vehicle
# it { should have_delegated_type(:drivable).deprecated }
# end
#
# # Minitest (Shoulda)
# class VehicleTest < ActiveSupport::TestCase
# should have_delegated_type(:drivable).deprecated
# end
#
# @return [AssociationMatcher]
#

def have_delegated_type(name)
AssociationMatcher.new(:belongs_to, name)
end
Expand Down Expand Up @@ -970,6 +1007,26 @@ def have_delegated_type(name)
# should have_many(:employees).inverse_of(:company)
# end
#
#
# ##### deprecated
#
# Use `deprecated` to assert that the `:deprecated` option was specified.
# (Enabled by default in Rails 8.1+)
#
# class Player < ActiveRecord::Base
# has_many :games, deprecated: true
# end
#
# # RSpec
# RSpec.describe Player, type: :model do
# it { should have_many(:games).deprecated(true) }
# end
#
# # Minitest (Shoulda)
# class PlayerTest < ActiveSupport::TestCase
# should have_many(:games).deprecated(true)
# end
#
# @return [AssociationMatcher]
#
def have_many(name)
Expand Down Expand Up @@ -1217,6 +1274,26 @@ def have_many(name)
# should have_one(:brain).required
# end
#
#
# ##### deprecated
#
# Use `deprecated` to assert that the `:deprecated` option was specified.
# (Enabled by default in Rails 8.1+).
#
# class Account < ActiveRecord::Base
# has_one :bank, deprecated: true
# end
#
# # RSpec
# RSpec.describe Account, type: :model do
# it { should have_one(:bank).deprecated(true) }
# end
#
# # Minitest (Shoulda)
# class AccountTest < ActiveSupport::TestCase
# should have_one(:bank).deprecated(true)
# end
#
# @return [AssociationMatcher]
#
def have_one(name)
Expand Down Expand Up @@ -1375,6 +1452,25 @@ def have_one(name)
# should have_and_belong_to_many(:advertisers).autosave(true)
# end
#
# ##### deprecated
#
# Use `deprecated` to assert that the `:deprecated` option was specified.
# (Enabled by default in Rails 8.1+).
#
# class Publisher < ActiveRecord::Base
# has_and_belongs_to_many :advertisers, deprecated: true
# end
#
# # RSpec
# RSpec.describe Publisher, type: :model do
# it { should have_and_belong_to_many(:advertisers).deprecated(true) }
# end
#
# # Minitest (Shoulda)
# class AccountTest < ActiveSupport::TestCase
# should have_and_belong_to_many(:advertisers).deprecated(true)
# end
#
# @return [AssociationMatcher]
#
def have_and_belong_to_many(name)
Expand Down Expand Up @@ -1546,6 +1642,16 @@ def join_table(join_table_name)
self
end

def deprecated(deprecated = true)
if Shoulda::Matchers::RailsShim.active_record_gte_8_1?
@options[:deprecated] = deprecated
self
else
raise NotImplementedError,
'`deprecated` association matcher is only available on Active Record >= 8.1.'
end
end

def without_validating_presence
remove_submatcher(AssociationMatchers::RequiredMatcher)
self
Expand Down Expand Up @@ -1586,6 +1692,7 @@ def matches?(subject)
touch_correct? &&
types_correct? &&
strict_loading_correct? &&
deprecated_correct? &&
submatchers_match?
end

Expand Down Expand Up @@ -1848,6 +1955,16 @@ def touch_correct?
end
end

def deprecated_correct?
if option_verifier.correct_for_boolean?(:deprecated, options[:deprecated])
true
else
@missing = "#{name} should have deprecated set to"\
" #{options[:deprecated]}"
false
end
end

def types_correct?
if options.key?(:types)
types = options[:types]
Expand Down
4 changes: 4 additions & 0 deletions lib/shoulda/matchers/rails_shim.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ def active_model_lt_7?
Gem::Requirement.new('< 7').satisfied_by?(active_model_version)
end

def active_record_gte_8_1?
Gem::Requirement.new('>= 8.1').satisfied_by?(active_record_version)
end

def generate_validation_message(
record,
attribute,
Expand Down
4 changes: 4 additions & 0 deletions spec/support/unit/helpers/active_record_versions.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,9 @@ def self.configure_example_group(example_group)
def active_record_version
Tests::Version.new(::ActiveRecord::VERSION::STRING)
end

def active_record_gte_8_1?
active_record_version >= '8.1'
end
end
end
Loading