class Shoulda::Matchers::ActiveModel::ValidatePresenceOfMatcher

@private

Public Class Methods

new(attribute) click to toggle source
# File lib/shoulda/matchers/active_model/validate_presence_of_matcher.rb, line 137
def initialize(attribute)
  super
  @expected_message = :blank
end

Public Instance Methods

does_not_match?(subject) click to toggle source
Calls superclass method
# File lib/shoulda/matchers/active_model/validate_presence_of_matcher.rb, line 161
def does_not_match?(subject)
  super(subject)

  possibly_ignore_interference_by_writer

  if secure_password_being_validated?
    ignore_interference_by_writer.default_to(when: :blank?)

    disallowed_values.any? do |value|
      allows_and_double_checks_value_of!(value)
    end
  else
    (expects_to_allow_nil? && disallows_value_of(nil)) ||
      disallowed_values.any? do |value|
        allows_original_or_typecast_value?(value)
      end
  end
end
failure_message() click to toggle source
Calls superclass method
# File lib/shoulda/matchers/active_model/validate_presence_of_matcher.rb, line 184
        def failure_message
          message = super

          if should_add_footnote_about_belongs_to?
            message << "\n\n"
            message << Shoulda::Matchers.word_wrap(<<-MESSAGE.strip, indent: 2)
You're getting this error because #{reason_for_existing_presence_validation}.
*This* presence validation doesn't use "can't be blank", the usual validation
message, but "must exist" instead.

With that said, did you know that the `belong_to` matcher can test this
validation for you? Instead of using `validate_presence_of`, try
#{suggestions_for_belongs_to}
            MESSAGE
          end

          message
        end
matches?(subject) click to toggle source
Calls superclass method
# File lib/shoulda/matchers/active_model/validate_presence_of_matcher.rb, line 142
def matches?(subject)
  super(subject)

  possibly_ignore_interference_by_writer

  if secure_password_being_validated? && Shoulda::Matchers::RailsShim.active_model_lt_7?
    ignore_interference_by_writer.default_to(when: :blank?)

    disallowed_values.all? do |value|
      disallows_and_double_checks_value_of!(value)
    end
  else
    (!expects_to_allow_nil? || allows_value_of(nil)) &&
      disallowed_values.all? do |value|
        disallows_original_or_typecast_value?(value)
      end
  end
end
simple_description() click to toggle source
# File lib/shoulda/matchers/active_model/validate_presence_of_matcher.rb, line 180
def simple_description
  "validate that :#{@attribute} cannot be empty/falsy"
end

Private Instance Methods

allows_and_double_checks_value_of!(value) click to toggle source
# File lib/shoulda/matchers/active_model/validate_presence_of_matcher.rb, line 216
def allows_and_double_checks_value_of!(value)
  allows_value_of(value, @expected_message)
rescue ActiveModel::AllowValueMatcher::AttributeChangedValueError
  raise ActiveModel::CouldNotSetPasswordError.create(model)
end
allows_original_or_typecast_value?(value) click to toggle source
# File lib/shoulda/matchers/active_model/validate_presence_of_matcher.rb, line 222
def allows_original_or_typecast_value?(value)
  allows_value_of(value, @expected_message)
end
association?() click to toggle source
# File lib/shoulda/matchers/active_model/validate_presence_of_matcher.rb, line 325
def association?
  association_reflection.present?
end
association_name() click to toggle source
# File lib/shoulda/matchers/active_model/validate_presence_of_matcher.rb, line 341
def association_name
  association_reflection.name
end
association_options() click to toggle source
# File lib/shoulda/matchers/active_model/validate_presence_of_matcher.rb, line 345
def association_options
  association_reflection&.options
end
association_reflection() click to toggle source
# File lib/shoulda/matchers/active_model/validate_presence_of_matcher.rb, line 349
def association_reflection
  model.try(:reflect_on_association, @attribute)
end
attachment?() click to toggle source
# File lib/shoulda/matchers/active_model/validate_presence_of_matcher.rb, line 335
def attachment?
  model_has_associations?(
    ["#{@attribute}_attachment", "#{@attribute}_attachments"],
  )
end
attribute_accepts_string_values?() click to toggle source
# File lib/shoulda/matchers/active_model/validate_presence_of_matcher.rb, line 314
def attribute_accepts_string_values?
  if association?
    false
  elsif attribute_serialization_coder.respond_to?(:object_class)
    attribute_serialization_coder.object_class == String
  else
    RailsShim.supports_full_attributes_api?(model) &&
      attribute_type.try(:type) == :string
  end
end
attribute_serialization_coder() click to toggle source
# File lib/shoulda/matchers/active_model/validate_presence_of_matcher.rb, line 359
def attribute_serialization_coder
  RailsShim.attribute_serialization_coder_for(model, @attribute)
end
attribute_type() click to toggle source
# File lib/shoulda/matchers/active_model/validate_presence_of_matcher.rb, line 363
def attribute_type
  RailsShim.attribute_type_for(model, @attribute)
end
belongs_to_association_being_validated?() click to toggle source
# File lib/shoulda/matchers/active_model/validate_presence_of_matcher.rb, line 310
def belongs_to_association_being_validated?
  association? && association_reflection.macro == :belongs_to
end
belongs_to_association_configured_to_be_required?() click to toggle source
# File lib/shoulda/matchers/active_model/validate_presence_of_matcher.rb, line 305
def belongs_to_association_configured_to_be_required?
  association_options[:optional] == false ||
    association_options[:required] == true
end
collection_association?() click to toggle source
# File lib/shoulda/matchers/active_model/validate_presence_of_matcher.rb, line 329
def collection_association?
  association? && [:has_many, :has_and_belongs_to_many].include?(
    association_reflection.macro,
  )
end
disallowed_values() click to toggle source
# File lib/shoulda/matchers/active_model/validate_presence_of_matcher.rb, line 236
def disallowed_values
  if collection_association?
    [Array.new]
  elsif attachment?
    [nil]
  else
    values = []

    if attribute_accepts_string_values?
      values << ''
    end

    if !expects_to_allow_nil?
      values << nil
    end

    values
  end
end
disallows_and_double_checks_value_of!(value) click to toggle source
# File lib/shoulda/matchers/active_model/validate_presence_of_matcher.rb, line 226
def disallows_and_double_checks_value_of!(value)
  disallows_value_of(value, @expected_message)
rescue ActiveModel::AllowValueMatcher::AttributeChangedValueError
  raise ActiveModel::CouldNotSetPasswordError.create(model)
end
disallows_original_or_typecast_value?(value) click to toggle source
# File lib/shoulda/matchers/active_model/validate_presence_of_matcher.rb, line 232
def disallows_original_or_typecast_value?(value)
  disallows_value_of(value, @expected_message)
end
example_of_belongs_to(with: nil) click to toggle source
# File lib/shoulda/matchers/active_model/validate_presence_of_matcher.rb, line 289
def example_of_belongs_to(with: nil)
  initial_call = "should belong_to(:#{association_name})"
  inside =
    if with
      "#{initial_call}.#{with.first}(#{with.second})"
    else
      initial_call
    end

  if Shoulda::Matchers.integrations.test_frameworks.any?(&:n_unit?)
    inside
  else
    "it { #{inside} }"
  end
end
model() click to toggle source
# File lib/shoulda/matchers/active_model/validate_presence_of_matcher.rb, line 371
def model
  @subject.class
end
model_has_associations?(associations) click to toggle source
# File lib/shoulda/matchers/active_model/validate_presence_of_matcher.rb, line 353
def model_has_associations?(associations)
  associations.any? do |association|
    !!model.try(:reflect_on_association, association)
  end
end
possibly_ignore_interference_by_writer() click to toggle source
# File lib/shoulda/matchers/active_model/validate_presence_of_matcher.rb, line 210
def possibly_ignore_interference_by_writer
  if secure_password_being_validated? && RailsShim.active_model_lt_7?
    ignore_interference_by_writer.default_to(when: :blank?)
  end
end
presence_validation_exists_on_attribute?() click to toggle source
# File lib/shoulda/matchers/active_model/validate_presence_of_matcher.rb, line 367
def presence_validation_exists_on_attribute?
  model._validators.include?(@attribute)
end
reason_for_existing_presence_validation() click to toggle source
# File lib/shoulda/matchers/active_model/validate_presence_of_matcher.rb, line 261
def reason_for_existing_presence_validation
  if belongs_to_association_configured_to_be_required?
    "you've instructed your `belongs_to` association to add a "\
      'presence validation to the attribute'
  else
    # assume ::ActiveRecord::Base.belongs_to_required_by_default == true
    'ActiveRecord is configured to add a presence validation to all '\
      '`belongs_to` associations, and this includes yours'
  end
end
secure_password_being_validated?() click to toggle source
# File lib/shoulda/matchers/active_model/validate_presence_of_matcher.rb, line 205
def secure_password_being_validated?
  Shoulda::Matchers::RailsShim.digestible_attributes_in(@subject).
    include?(@attribute)
end
should_add_footnote_about_belongs_to?() click to toggle source
# File lib/shoulda/matchers/active_model/validate_presence_of_matcher.rb, line 256
def should_add_footnote_about_belongs_to?
  belongs_to_association_being_validated? &&
    presence_validation_exists_on_attribute?
end
suggestions_for_belongs_to() click to toggle source
# File lib/shoulda/matchers/active_model/validate_presence_of_matcher.rb, line 272
        def suggestions_for_belongs_to
          if belongs_to_association_configured_to_be_required?
            <<~MESSAGE
              one of the following instead, depending on your use case:

                    #{example_of_belongs_to(with: [:optional, false])}
                    #{example_of_belongs_to(with: [:required, true])}
            MESSAGE
          else
            <<~MESSAGE
              the following instead:

                    #{example_of_belongs_to}
            MESSAGE
          end
        end