JSON Serializers: The Contract with Ember
PostSerializer is the single source of truth for what a Post looks like as JSON to the Ember frontend: it picks which ActiveRecord attributes and computed values are exposed, under what conditions, and with what key names. Because the Ember Post model reads these keys directly onto tracked properties, any rename, removal, or conditional-inclusion change here has to be mirrored on the frontend or the UI silently breaks. This module walks through the attribute declarations, the include_*? conditional pattern, and the opts-driven instance variables that let one serializer class render many different contexts (topic view vs single post vs notifications).
Passing extra context into the serializer
app/serializers/post_serializer.rb · lines 3–18PostSerializer inherits from BasicPostSerializer, so it only needs to declare the fields that are specific to viewing a full post (BasicPostSerializer already covers the bare minimum like cooked and username).
INSTANCE_VARS lists flags and data (add_title, add_excerpt, draft_sequence, etc.) that aren't on the Post model at all — they're contextual switches the caller passes in, e.g. 'include the excerpt for this render' or 'here are the post_actions I already loaded in bulk'.
This metaprogramming line dynamically defines an attr_accessor for every name in INSTANCE_VARS, so methods below can read @add_title, @add_excerpt, etc. as plain ivars.
class PostSerializer < BasicPostSerializer # To pass in additional information we might need INSTANCE_VARS = %i[ parent_post add_raw add_title single_post_link_counts draft_sequence post_actions all_post_actions add_excerpt notice_created_by_users ignored_user_like_counts ] INSTANCE_VARS.each { |v| public_send(:attr_accessor, v) }
def initialize(object, opts) super(object, opts) PostSerializer::INSTANCE_VARS.each do |name| public_send("#{name}=", opts[name]) if opts.include? name end end
app/serializers/post_serializer.rb · lines 107–113PostSerializer.new(post, opts) (e.g. add_title: true, add_excerpt: true) is copied onto the matching instance variables here. Those ivars then drive the include_*? predicate methods that decide which optional fields make it into the JSON.def include_topic_title? @add_title end def include_topic_html_title? @add_title end def include_category_id? @add_title end def include_excerpt? @add_excerpt end def include_truncated? @add_excerpt end
app/serializers/post_serializer.rb · lines 123–141include_<attribute>? method for each declared attribute; when it returns falsy, the key is omitted from the JSON entirely (not sent as null). This is how the same serializer renders a lean payload for a topic listing and a richer one for a single-post view, controlled by the add_title/add_excerpt flags set during initialize.Check your understanding
Answered in place — nothing is graded, everything is explained. 0 / 2 passed
What determines whether `topic_title` shows up in a post's serialized JSON at all?
Where do flags like `add_title` and `add_excerpt` come from before they control which attributes are included?