I have a use case where I’d like a record to validate a nested has_many
association, but only those nested records which meet a certain condition (or in this case, only those which don’t).
This isn’t the same as if:
/unless:
which are conditions on the main record (which I also have), but rather only:
/except:
, e.g.
validates_associated :credentials, on: :update, unless: :allow_incomplete?, except: :expired?
We’ve achieved this by monkey-patching AssociatedValidator
like so:
module ActiveRecord
module Validations
class AssociatedValidator < ActiveModel::EachValidator
def validate_each(record, attribute, value)
opts = options.dup
conditions = opts.extract! :only, :except
if Array(value).any? { |r| invalid_object?(r, **conditions) }
record.errors.add(attribute, :invalid, **opts.merge(value: value))
end
end
private
def invalid_object?(record, only: proc { true }, except: proc { false })
!record.try(:marked_for_destruction?) &&
only.to_proc.call(record) &&
!except.to_proc.call(record) &&
!record.valid?
end
end
end
end
I was going to open this as a PR but guidelines advise proposing it here first. Is this an okay idea?