Skip to content

Commit

Permalink
Add better serialization_scope tests; uncover bug
Browse files Browse the repository at this point in the history
  • Loading branch information
bf4 committed Feb 10, 2016
1 parent c8a73b0 commit fd544ad
Show file tree
Hide file tree
Showing 2 changed files with 195 additions and 35 deletions.
2 changes: 2 additions & 0 deletions lib/active_model/serializer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,8 @@ def self._serializer_instance_method_defined?(name)
_serializer_instance_methods.include?(name)
end

# TODO: Fix load-order failures when different serializer instances define different
# scope methods
def self._serializer_instance_methods
@_serializer_instance_methods ||= (public_instance_methods - Object.public_instance_methods).to_set
end
Expand Down
228 changes: 193 additions & 35 deletions test/action_controller/serialization_scope_name_test.rb
Original file line number Diff line number Diff line change
@@ -1,63 +1,221 @@
require 'test_helper'
require 'pathname'

class DefaultScopeNameTest < ActionController::TestCase
class UserSerializer < ActiveModel::Serializer
module SerializationScopeTesting
class User < ActiveModelSerializers::Model
attr_accessor :id, :name, :admin
def admin?
current_user.admin
admin
end
attributes :admin?
end
class Comment < ActiveModelSerializers::Model
attr_accessor :id, :body
end
class Post < ActiveModelSerializers::Model
attr_accessor :id, :title, :body, :comments
end
class PostSerializer < ActiveModel::Serializer
attributes :id, :title, :body, :comments

class UserTestController < ActionController::Base
protect_from_forgery

before_action { request.format = :json }
def body
"The 'scope' is the 'current_user': #{scope == current_user}"
end

def current_user
User.new(id: 1, name: 'Pete', admin: false)
def comments
if current_user.admin?
[Comment.new(id: 1, body: 'Admin')]
else
[Comment.new(id: 2, body: 'Scoped')]
end
end

def render_new_user
render json: User.new(id: 1, name: 'Pete', admin: false), serializer: UserSerializer, adapter: :json_api
def json_key
'post'
end
end
class PostTestController < ActionController::Base
attr_accessor :current_user
def render_post_by_non_admin
self.current_user = User.new(id: 3, name: 'Pete', admin: false)
render json: new_post, serializer: serializer, adapter: :json
end

tests UserTestController
def render_post_by_admin
self.current_user = User.new(id: 3, name: 'Pete', admin: true)
render json: new_post, serializer: serializer, adapter: :json
end

private

def test_default_scope_name
get :render_new_user
assert_equal '{"data":{"id":"1","type":"users","attributes":{"admin?":false}}}', @response.body
def new_post
Post.new(id: 4, title: 'Title')
end

def serializer
PostSerializer
end
end
end
class PostViewContextSerializer < PostSerializer
def body
"The 'scope' is the 'view_context': #{scope == view_context}"
end

class SerializationScopeNameTest < ActionController::TestCase
class AdminUserSerializer < ActiveModel::Serializer
def admin?
current_admin.admin
def comments
if view_context.controller.current_user.admin?
[Comment.new(id: 1, body: 'Admin')]
else
[Comment.new(id: 2, body: 'Scoped')]
end
end
end
class DefaultScopeTest < ActionController::TestCase
tests PostTestController

def test_default_serialization_scope
assert_equal :current_user, @controller._serialization_scope
end

def test_default_serialization_scope_object
assert_equal @controller.current_user, @controller.serialization_scope
end

def test_default_scope_non_admin
get :render_post_by_non_admin
expected_json = {
post: {
id: 4,
title: 'Title',
body: "The 'scope' is the 'current_user': true",
comments: [
{ id: 2, body: 'Scoped' }
]
}
}.to_json
assert_equal expected_json, @response.body
end

def test_default_scope_admin
get :render_post_by_admin
expected_json = {
post: {
id: 4,
title: 'Title',
body: "The 'scope' is the 'current_user': true",
comments: [
{ id: 1, body: 'Admin' }
]
}
}.to_json
assert_equal expected_json, @response.body
end
attributes :admin?
end
class SerializationScopeTest < ActionController::TestCase
class PostViewContextTestController < PostTestController
serialization_scope :view_context

private

def serializer
PostViewContextSerializer
end
end
tests PostViewContextTestController

class AdminUserTestController < ActionController::Base
protect_from_forgery
def test_defined_serialization_scope
assert_equal :view_context, @controller._serialization_scope
end

serialization_scope :current_admin
before_action { request.format = :json }
def test_defined_serialization_scope_object
assert_equal @controller.view_context.class, @controller.serialization_scope.class
end

def current_admin
User.new(id: 2, name: 'Bob', admin: true)
def test_serialization_scope_non_admin
get :render_post_by_non_admin
expected_json = {
post: {
id: 4,
title: 'Title',
body: "The 'scope' is the 'view_context': true",
comments: [
{ id: 2, body: 'Scoped' }
]
}
}.to_json
assert_equal expected_json, @response.body
end

def render_new_user
render json: User.new(id: 1, name: 'Pete', admin: false), serializer: AdminUserSerializer, adapter: :json_api
def test_serialization_scope_admin
get :render_post_by_admin
expected_json = {
post: {
id: 4,
title: 'Title',
body: "The 'scope' is the 'view_context': true",
comments: [
{ id: 1, body: 'Admin' }
]
}
}.to_json
assert_equal expected_json, @response.body
end
end
class NilSerializationScopeTest < ActionController::TestCase
class PostViewContextTestController < ActionController::Base
serialization_scope nil

attr_accessor :current_user

def render_post_with_no_scope
self.current_user = User.new(id: 3, name: 'Pete', admin: false)
render json: new_post, serializer: PostSerializer, adapter: :json
end

tests AdminUserTestController
# TODO: run test when
# global state in Serializer._serializer_instance_methods is fixed
# def render_post_with_passed_in_scope
# self.current_user = User.new(id: 3, name: 'Pete', admin: false)
# render json: new_post, serializer: PostSerializer, adapter: :json, scope: current_user, scope_name: :current_user
# end

private

def new_post
Post.new(id: 4, title: 'Title')
end
end
tests PostViewContextTestController

def test_nil_serialization_scope
assert_nil @controller._serialization_scope
end

def test_nil_serialization_scope_object
assert_nil @controller.serialization_scope
end

# TODO: change to NoMethodError and match 'admin?' when the
# global state in Serializer._serializer_instance_methods is fixed
def test_nil_scope
exception = assert_raises(NameError) do
get :render_post_with_no_scope
end
assert_match /admin|current_user/, exception.message
end

def test_override_scope_name_with_controller
get :render_new_user
assert_equal '{"data":{"id":"1","type":"users","attributes":{"admin?":true}}}', @response.body
# TODO: run test when
# global state in Serializer._serializer_instance_methods is fixed
# def test_nil_scope_passed_in_current_user
# get :render_post_with_passed_in_scope
# expected_json = {
# post: {
# id: 4,
# title: 'Title',
# body: "The 'scope' is the 'current_user': true",
# comments: [
# { id: 2, body: 'Scoped' }
# ]
# }
# }.to_json
# assert_equal expected_json, @response.body
# end
end
end

0 comments on commit fd544ad

Please sign in to comment.