active_model_serializers/test/action_controller/serialization_scope_name_test.rb
Benjamin Fleischer af99c0d9e6 Ensure inheritance hooks run
I was seeing transient failures where adapters may not be registered.

e.g. https://travis-ci.org/rails-api/active_model_serializers/builds/77735382

Since we're using the Adapter, JsonApi, and Json classes
as namespaces, some of the conventions we use for modules don't apply.
Basically, we don't want to define the class anywhere besides itself.
Otherwise, the inherited hooks may not run, and some adapters may not
be registered.

For example:

If we have a class Api `class Api; end`
And Api is also used as a namespace for `Api::Product`
And the classes are defined in different files.

In one file:

```ruby
class Api
  autoload :Product
  def self.inherited(subclass)
    puts
    p [:inherited, subclass.name]
    puts
  end
end
```

And in another:

```ruby
class Api
  class Product < Api
    def sell_sell_sell!
      # TODO: sell
    end
  end
end
```

If we load the Api class file first, the inherited hook will be defined on the class
so that when we load the Api::Product class, we'll see the output:

```plain
[ :inherited, Api::Product]
```

However, if we load the Api::Product class first, since it defines the `Api` class
and then inherited from it, the Api file was never loaded, the hook never defined,
and thus never run.

By defining the class as `class Api::Product < Api` We ensure the the Api class
MUST be defined, and thus, the hook will be defined and run and so sunshine and unicorns.

Appendix:

The below would work, but triggers a circular reference warning.
It's also not recommended to mix require with autoload.

```ruby
require 'api'
class Api
  class Product < Api
    def sell_sell_sell!
      # TODO: sell
    end
  end
end
```

This failure scenario was introduced by removing the circular reference warnings in
https://github.com/rails-api/active_model_serializers/pull/1067

Style note:

To make diffs on the adapters smalleer and easier to read, I've maintained the same
identention that was in the original file.  I've decided to prefer ease of reading
the diff over style, esp. since we may later return to the preferred class declaration style.

 with '#' will be ignored, and an empty message aborts the commit.
2015-09-09 08:55:20 -05:00

68 lines
1.7 KiB
Ruby

require 'test_helper'
require 'pathname'
class DefaultScopeNameTest < ActionController::TestCase
class UserSerializer < ActiveModel::Serializer
attributes :admin?
ActiveModelSerializers.silence_warnings do
def admin?
current_user.admin
end
end
end
class UserTestController < ActionController::Base
protect_from_forgery
before_filter { request.format = :json }
def current_user
User.new(id: 1, name: 'Pete', admin: false)
end
def render_new_user
render json: User.new(id: 1, name: 'Pete', admin: false), serializer: UserSerializer, adapter: :json_api
end
end
tests UserTestController
def test_default_scope_name
get :render_new_user
assert_equal '{"data":{"id":"1","type":"users","attributes":{"admin?":false}}}', @response.body
end
end
class SerializationScopeNameTest < ActionController::TestCase
class AdminUserSerializer < ActiveModel::Serializer
attributes :admin?
ActiveModelSerializers.silence_warnings do
def admin?
current_admin.admin
end
end
end
class AdminUserTestController < ActionController::Base
protect_from_forgery
serialization_scope :current_admin
before_filter { request.format = :json }
def current_admin
User.new(id: 2, name: 'Bob', admin: true)
end
def render_new_user
render json: User.new(id: 1, name: 'Pete', admin: false), serializer: AdminUserSerializer, adapter: :json_api
end
end
tests AdminUserTestController
def test_override_scope_name_with_controller
get :render_new_user
assert_equal '{"data":{"id":"1","type":"users","attributes":{"admin?":true}}}', @response.body
end
end