ActiveRecord::AttributeMethods has a handy #accessed_fields
method to track which attributes have been read: https://api.rubyonrails.org/classes/ActiveRecord/AttributeMethods.html#method-i-accessed_fields
I would like to add a similar #assigned_fields
method to track which attributes have been written.
My use case is that I want to conditionally run certain callbacks only if an attribute has been set, regardless of whether its value changed.
Specifically, I have a Profile model with an approved
boolean. Profiles may be of various types (businesses, non-profits, etc.). Some profile types are approved by default, others are not. In a before_save
callback, when a profile’s type has changed, its approved
boolean must be reset to the new type’s default unless a value for approved
has been explicitly provided.
I’ve enabled this in my codebase by adding a couple methods:
class ActiveModel::AttributeSet
def assigned
attributes.each_key.select { |name| self[name].send(:assigned?) }
end
end
module ActiveRecord::AttributeMethods
# Tracks which attributes have been assigned a value,
# even if no mutation has occurred.
def assigned_fields
@attributes.assigned
end
end
And my callback conditions look something like this:
before_save :reset_approval,
if: proc { |profile|
profile.profile_type_changed? &&
!profile.assigned_fields.include?('approved')
}
I intend to submit a PR implementing this feature, but first wanted to poll the community to get a sense of whether others might find this as useful as I do.