def _assign_attribute(k, v)
setter = :"#{k}="
if respond_to?(setter)
public_send(setter, v)
else
raise UnknownAttributeError.new(self, k) # πππ
end
end
# The following methods were pulled from Rails ActiveModel and modified
# to not raise an UnknownAttributeError when an attribute in the data we
# get back from an API, like the Identity Realm API, does not have a
# corresponding setter method (attr_accessor/attr_writer) defined in a Class.
# https://github.com/rails/rails/blob/09a2979f75c51afb797dd60261a8930f84144af8/activemodel/lib/active_model/attribute_assignment.rb
#
# Example: A "Car" class that uses this model defines attr_accessors for :make, :model, and :year.
# The Car API that we get car data from only returns make, model, and year right now, so all is well.
# Eventually the Car API adds "color" to the data that it returns. With the standard Rails ActiveModel
# this would cause an UnknownAttributeError because our Car class does not define a :color setter.
# Instead, with the modified code below all of the attributes we have defined will be assigned a value
# and any extra data attributes that come from the API will simply be dropped w/o disrupting the application.
#
# This makes our classes that use this model more resilient to API changes (that we don't control),
# AND allows us to ignore fields like "last_updated" and "first_created" that an API may include w/ data.
def assign_attributes(new_attributes)
if !new_attributes.respond_to?(:stringify_keys)
raise ArgumentError, "When assigning attributes, you must pass a hash as an argument, #{new_attributes.class} passed."
end
return if new_attributes.empty?
attributes = new_attributes.stringify_keys
_assign_attributes(attributes)
end
def _assign_attributes(attributes)
attributes.each do |k, v|
_assign_attribute(k, v)
end
end
def _assign_attribute(k, v)
setter = :"#{k}="
if respond_to?(setter)
public_send(setter, v)
end
end
rails/attribute_assignment.rb at 09a2979f75c51afb797dd60261a8930f84144af8 Β· rails/rails Β· GitHub
shoutout to my man @SamL_not_SAML