# frozen_string_literal: true require 'test_helper' module ActionController module Serialization class Json class IncludeTest < ActionController::TestCase INCLUDE_STRING = 'posts.comments'.freeze INCLUDE_HASH = { posts: :comments }.freeze DEEP_INCLUDE = 'posts.comments.author'.freeze class IncludeTestController < ActionController::Base def setup_data ActionController::Base.cache_store.clear @author = Author.new(id: 1, name: 'Steve K.') @post = Post.new(id: 42, title: 'New Post', body: 'Body') @first_comment = Comment.new(id: 1, body: 'ZOMG A COMMENT') @second_comment = Comment.new(id: 2, body: 'ZOMG ANOTHER COMMENT') @post.comments = [@first_comment, @second_comment] @post.author = @author @first_comment.post = @post @second_comment.post = @post @blog = Blog.new(id: 1, name: 'My Blog!!') @post.blog = @blog @author.posts = [@post] @first_comment.author = @author @second_comment.author = @author @author.comments = [@first_comment, @second_comment] @author.roles = [] @author.bio = {} end def render_without_include setup_data render json: @author, adapter: :json end def render_resource_with_include_hash setup_data render json: @author, include: INCLUDE_HASH, adapter: :json end def render_resource_with_include_string setup_data render json: @author, include: INCLUDE_STRING, adapter: :json end def render_resource_with_deep_include setup_data render json: @author, include: DEEP_INCLUDE, adapter: :json end def render_without_recursive_relationships # testing recursive includes ('**') can't have any cycles in the # relationships, or we enter an infinite loop. author = Author.new(id: 11, name: 'Jane Doe') post = Post.new(id: 12, title: 'Hello World', body: 'My first post') comment = Comment.new(id: 13, body: 'Commentary') author.posts = [post] post.comments = [comment] render json: author end end tests IncludeTestController def test_render_without_include get :render_without_include response = JSON.parse(@response.body) expected = { 'author' => { 'id' => 1, 'name' => 'Steve K.', 'posts' => [ { 'id' => 42, 'title' => 'New Post', 'body' => 'Body' } ], 'roles' => [], 'bio' => {} } } assert_equal(expected, response) end def test_render_resource_with_include_hash get :render_resource_with_include_hash response = JSON.parse(@response.body) assert_equal(expected_include_response, response) end def test_render_resource_with_include_string get :render_resource_with_include_string response = JSON.parse(@response.body) assert_equal(expected_include_response, response) end def test_render_resource_with_deep_include get :render_resource_with_deep_include response = JSON.parse(@response.body) assert_equal(expected_deep_include_response, response) end def test_render_with_empty_default_includes with_default_includes '' do get :render_without_include response = JSON.parse(@response.body) expected = { 'author' => { 'id' => 1, 'name' => 'Steve K.' } } assert_equal(expected, response) end end def test_render_with_recursive_default_includes with_default_includes '**' do get :render_without_recursive_relationships response = JSON.parse(@response.body) expected = { 'id' => 11, 'name' => 'Jane Doe', 'roles' => nil, 'bio' => nil, 'posts' => [ { 'id' => 12, 'title' => 'Hello World', 'body' => 'My first post', 'comments' => [ { 'id' => 13, 'body' => 'Commentary', 'post' => nil, # not set to avoid infinite recursion 'author' => nil, # not set to avoid infinite recursion } ], 'blog' => { 'id' => 999, 'name' => 'Custom blog', 'writer' => nil, 'articles' => nil }, 'author' => nil # not set to avoid infinite recursion } ] } assert_equal(expected, response) end end def test_render_with_includes_overrides_default_includes with_default_includes '' do get :render_resource_with_include_hash response = JSON.parse(@response.body) assert_equal(expected_include_response, response) end end private def expected_include_response { 'author' => { 'id' => 1, 'name' => 'Steve K.', 'posts' => [ { 'id' => 42, 'title' => 'New Post', 'body' => 'Body', 'comments' => [ { 'id' => 1, 'body' => 'ZOMG A COMMENT' }, { 'id' => 2, 'body' => 'ZOMG ANOTHER COMMENT' } ] } ] } } end def expected_deep_include_response { 'author' => { 'id' => 1, 'name' => 'Steve K.', 'posts' => [ { 'id' => 42, 'title' => 'New Post', 'body' => 'Body', 'comments' => [ { 'id' => 1, 'body' => 'ZOMG A COMMENT', 'author' => { 'id' => 1, 'name' => 'Steve K.' } }, { 'id' => 2, 'body' => 'ZOMG ANOTHER COMMENT', 'author' => { 'id' => 1, 'name' => 'Steve K.' } } ] } ] } } end def with_default_includes(include_directive) original = ActiveModelSerializers.config.default_includes ActiveModelSerializers.config.default_includes = include_directive clear_include_directive_cache yield ensure ActiveModelSerializers.config.default_includes = original clear_include_directive_cache end def clear_include_directive_cache ActiveModelSerializers .instance_variable_set(:@default_include_directive, nil) end end end end end