There is an inconsistency on how add_to_serializer
works between development and production. This is due how plugins are applied
https://github.com/discourse/discourse/blob/master/lib/plugin/instance.rb#L600-L610
Given we reload the code in development, every modification we do to a parent serializer, children will pick them up. To reproduce this inconsistency you can execute the code below
add_to_serializer(:basic_user, :created_at) { user.created_at }
If you execute this in development, all descendants of BasicUserSerializer
will have the created_at
attribute. In production only BasicUserSerializer
will have that attribute.
UserNameSerializer._attributes
=> {:id=>:id, :username=>:username, :avatar_template=>:avatar_template, :name=>:name, :title=>:title}
BasicUserSerializer._attributes
=> {:id=>:id, :username=>:username, :avatar_template=>:avatar_template, :created_at=>:created_at}
The problem is due how ActiveModel::Serializer
works, and I’m not sure if they want to support this use case, they only get the attributes from the parent once when you call the attributes(*attrs)
method.
Workaround
Here’s a workaround to this problem, this is how I’m dealing with it atm.
Inside a plugin do
after_initialize do
# Monkey patch ActiveModel::Serializer to allow us
# reload children serializers attributes after parent is modified
class ::ActiveModel::Serializer
# Update _attributes with superclass _attributes
def self.reload
self._attributes = _attributes.merge(superclass._attributes)
end
end
add_to_serializer(:basic_user, :created_at) { user.created_at }
# Reload all children serializers, so they include :created_at
BasicUserSerializer.descendants.each(&:reload)
end
I saw some PRs from you @sam in the AMS repo, maybe you can take a look at this.
Thanks!