mirror of
https://github.com/thoughtbot/shoulda-matchers.git
synced 2022-11-09 12:01:38 -05:00
Add without_presence_validation q to belong_to
With the new Rails 5 behavior, `belong_to` will check to ensure that the association has a presence validation on it. In some cases, however, this is not desirable. For instance, say we have this setup: class Employee < ApplicationRecord # Assume belongs_to_required_by_default is true belongs_to :manager before_validation :add_manager private def add_manager self.manager = Manager.create end end In this case, even though the association is effectively defined with `required: true`, the ensuing presence validation never fails, because `manager` is always set to something before validations kick off. So this test won't work: it { should belong_to(:manager) } To get around this, this commit allows us to say: it { should belong_to(:manager).without_presence_validation } which instructs the matcher not to test for any presence (or absence, for that matter) of a presence validation, mimicking the pre-Rails 5 behavior.
This commit is contained in:
parent
ca6a1ff9ee
commit
707d87dbd6
3 changed files with 140 additions and 0 deletions
7
NEWS.md
7
NEWS.md
|
@ -91,6 +91,11 @@ is now:
|
|||
* *Original PR: [#956]*
|
||||
* *Original issues: [#870], [#861]*
|
||||
|
||||
* Add `without_presence_validation` qualifier to `belong_to` to get around the
|
||||
fact that `required` is assumed, above.
|
||||
|
||||
* *Original issues: [#1153], [#1154]*
|
||||
|
||||
* Add `allow_nil` qualifier to `delegate_method`.
|
||||
|
||||
* *Commit: [d49cfca]*
|
||||
|
@ -147,6 +152,8 @@ is now:
|
|||
[#956]: https://github.com/thoughtbot/shoulda-matchers/pulls/956
|
||||
[#870]: https://github.com/thoughtbot/shoulda-matchers/issues/870
|
||||
[#861]: https://github.com/thoughtbot/shoulda-matchers/issues/861
|
||||
[#1153]: https://github.com/thoughtbot/shoulda-matchers/issues/1153
|
||||
[#1154]: https://github.com/thoughtbot/shoulda-matchers/issues/1154
|
||||
[#954]: https://github.com/thoughtbot/shoulda-matchers/issues/954
|
||||
[#1074]: https://github.com/thoughtbot/shoulda-matchers/pulls/1074
|
||||
[#1075]: https://github.com/thoughtbot/shoulda-matchers/pulls/1075
|
||||
|
|
|
@ -272,6 +272,35 @@ module Shoulda
|
|||
# should belong_to(:organization).required
|
||||
# end
|
||||
#
|
||||
# #### without_presence_validation
|
||||
#
|
||||
# Use `without_presence_validation` with `belong_to` to prevent the
|
||||
# matcher from checking whether the association disallows nil (Rails 5+
|
||||
# only). This can be helpful if you have a custom hook that always sets
|
||||
# the association to a meaningful value:
|
||||
#
|
||||
# class Person < ActiveRecord::Base
|
||||
# belongs_to :organization
|
||||
#
|
||||
# before_validation :autoassign_organization
|
||||
#
|
||||
# private
|
||||
#
|
||||
# def autoassign_organization
|
||||
# self.organization = Organization.create!
|
||||
# end
|
||||
# end
|
||||
#
|
||||
# # RSpec
|
||||
# describe Person
|
||||
# it { should belong_to(:organization).without_presence_validation }
|
||||
# end
|
||||
#
|
||||
# # Minitest (Shoulda)
|
||||
# class PersonTest < ActiveSupport::TestCase
|
||||
# should belong_to(:organization).without_presence_validation
|
||||
# end
|
||||
#
|
||||
# ##### optional
|
||||
#
|
||||
# Use `optional` to assert that the association is allowed to be nil.
|
||||
|
@ -1092,6 +1121,11 @@ module Shoulda
|
|||
self
|
||||
end
|
||||
|
||||
def without_validating_presence
|
||||
remove_submatcher(AssociationMatchers::RequiredMatcher)
|
||||
self
|
||||
end
|
||||
|
||||
def description
|
||||
description = "#{macro_description} #{name}"
|
||||
description += " class_name => #{options[:class_name]}" if options.key?(:class_name)
|
||||
|
|
|
@ -616,6 +616,105 @@ describe Shoulda::Matchers::ActiveRecord::AssociationMatcher, type: :model do
|
|||
end
|
||||
end
|
||||
|
||||
if active_record_supports_optional_for_associations?
|
||||
context 'when the model ensures the association is set' do
|
||||
context 'and the matcher is not qualified with anything' do
|
||||
context 'and the matcher is not qualified with without_validating_presence' do
|
||||
it 'fails with an appropriate message' do
|
||||
model = create_child_model_belonging_to_parent do
|
||||
before_validation :ensure_parent_is_set
|
||||
|
||||
def ensure_parent_is_set
|
||||
self.parent = Parent.create
|
||||
end
|
||||
end
|
||||
|
||||
assertion = lambda do
|
||||
configuring_default_belongs_to_requiredness(true) do
|
||||
expect(model.new).to belong_to(:parent)
|
||||
end
|
||||
end
|
||||
|
||||
message = format_message(<<-MESSAGE, one_line: true)
|
||||
Expected Child to have a belongs_to association called parent (and
|
||||
for the record to fail validation if :parent is unset; i.e.,
|
||||
either the association should have been defined with `required:
|
||||
true`, or there should be a presence validation on :parent)
|
||||
MESSAGE
|
||||
|
||||
expect(&assertion).to fail_with_message(message)
|
||||
end
|
||||
end
|
||||
|
||||
context 'and the matcher is qualified with without_validating_presence' do
|
||||
it 'passes' do
|
||||
model = create_child_model_belonging_to_parent do
|
||||
before_validation :ensure_parent_is_set
|
||||
|
||||
def ensure_parent_is_set
|
||||
self.parent = Parent.create
|
||||
end
|
||||
end
|
||||
|
||||
configuring_default_belongs_to_requiredness(true) do
|
||||
expect(model.new).
|
||||
to belong_to(:parent).
|
||||
without_validating_presence
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'and the matcher is qualified with required' do
|
||||
context 'and the matcher is not qualified with without_validating_presence' do
|
||||
it 'fails with an appropriate message' do
|
||||
model = create_child_model_belonging_to_parent do
|
||||
before_validation :ensure_parent_is_set
|
||||
|
||||
def ensure_parent_is_set
|
||||
self.parent = Parent.create
|
||||
end
|
||||
end
|
||||
|
||||
assertion = lambda do
|
||||
configuring_default_belongs_to_requiredness(true) do
|
||||
expect(model.new).to belong_to(:parent).required
|
||||
end
|
||||
end
|
||||
|
||||
message = format_message(<<-MESSAGE, one_line: true)
|
||||
Expected Child to have a belongs_to association called parent
|
||||
(and for the record to fail validation if :parent is unset; i.e.,
|
||||
either the association should have been defined with `required:
|
||||
true`, or there should be a presence validation on :parent)
|
||||
MESSAGE
|
||||
|
||||
expect(&assertion).to fail_with_message(message)
|
||||
end
|
||||
end
|
||||
|
||||
context 'and the matcher is also qualified with without_validating_presence' do
|
||||
it 'passes' do
|
||||
model = create_child_model_belonging_to_parent do
|
||||
before_validation :ensure_parent_is_set
|
||||
|
||||
def ensure_parent_is_set
|
||||
self.parent = Parent.create
|
||||
end
|
||||
end
|
||||
|
||||
configuring_default_belongs_to_requiredness(true) do
|
||||
expect(model.new).
|
||||
to belong_to(:parent).
|
||||
required.
|
||||
without_validating_presence
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def belonging_to_parent(options = {}, parent_options = {}, &block)
|
||||
child_model = create_child_model_belonging_to_parent(
|
||||
options,
|
||||
|
|
Loading…
Add table
Reference in a new issue