Skip to content

Sideload root only #353

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 23 additions & 2 deletions lib/active_model/serializer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ def to_s
class_attribute :_embed
self._embed = :objects
class_attribute :_root_embed
class_attribute :_root_only

class_attribute :cache
class_attribute :perform_caching
Expand Down Expand Up @@ -249,6 +250,7 @@ def model_class
def embed(type, options={})
self._embed = type
self._root_embed = true if options[:include]
self._root_only = true if options[:root_only]
end

# Defines the root used on serialization. If false, disables the root.
Expand Down Expand Up @@ -379,21 +381,40 @@ def include!(name, options={})

options = default_embed_options.merge!(options)
options[:value] ||= send(name)
association = association_class.new(name, options, self.options)

serializer_options = self.options.dup

if include_root_associations_only?
serializer_options[:include_root_only] = !root_serializer?
end

association = association_class.new(name, options, serializer_options)

if association.embed_ids?
node[association.key] = association.serialize_ids

if association.embed_in_root? && hash.nil?
raise IncludeError.new(self.class, association.name)
elsif association.embed_in_root? && association.embeddable?
merge_association hash, association.root, association.serializables, unique_values
if include_root_associations_only? && root_serializer?
merge_association hash, association.root, association.serializables, unique_values
elsif !include_root_associations_only?
merge_association hash, association.root, association.serializables, unique_values
end
end
elsif association.embed_objects?
node[association.key] = association.serialize
end
end

def include_root_associations_only?
options.key? :include_root_only
end

def root_serializer?
options[:include_root_only] == true
end

# In some cases, an Array of associations is built by merging the associated
# content for all of the children. For instance, if a Post has_many comments,
# which has_many tags, the top-level :tags key will contain the merged list
Expand Down
48 changes: 48 additions & 0 deletions test/serializer_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1518,4 +1518,52 @@ def test_only_option_takes_precedence_over_custom_defined_include_methods
}
}, post_serializer.as_json)
end

def test_sideloading_can_be_configured_on_only_the_root_object
adam = User.new name: 'Adam Hawkins', id: 1

post1 = Post.new title: "Post 1", id: 1
post2 = Post.new title: "Post 2", id: 2

post1.author = adam
post2.author = adam

post_serializer_class = Class.new(ActiveModel::Serializer) do
embed :id, include: true
has_one :author
attributes :id, :title
end

user_serializer_class = Class.new(ActiveModel::Serializer) do
embed :id, include: true
has_many :posts
attributes :id, :name
end

adam.class_eval do
define_method :active_model_serializer do
user_serializer_class
end

define_method :posts do
[post1, post2]
end
end

[post1, post2].each do |user|
user.class_eval do
define_method :active_model_serializer do
post_serializer_class
end
end
end

post_serializer = post_serializer_class.new post1, root: :post, include_root_only: true
hash = post_serializer.as_json

assert_equal({
post: { id: 1, title: 'Post 1', author_id: 1 },
authors: [{ id: 1, name: 'Adam Hawkins', post_ids: [1,2] }]
}, hash)
end
end