active_model_serializers_custom 0.10.90
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.github/ISSUE_TEMPLATE.md +29 -0
- data/.github/PULL_REQUEST_TEMPLATE.md +15 -0
- data/.gitignore +35 -0
- data/.rubocop.yml +109 -0
- data/.simplecov +110 -0
- data/.travis.yml +63 -0
- data/CHANGELOG.md +727 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/CONTRIBUTING.md +105 -0
- data/Gemfile +74 -0
- data/MIT-LICENSE +22 -0
- data/README.md +305 -0
- data/Rakefile +76 -0
- data/active_model_serializers.gemspec +64 -0
- data/appveyor.yml +28 -0
- data/bin/bench +171 -0
- data/bin/bench_regression +316 -0
- data/bin/rubocop +38 -0
- data/bin/serve_benchmark +39 -0
- data/docs/README.md +41 -0
- data/docs/STYLE.md +58 -0
- data/docs/general/adapters.md +269 -0
- data/docs/general/caching.md +58 -0
- data/docs/general/configuration_options.md +185 -0
- data/docs/general/deserialization.md +100 -0
- data/docs/general/fields.md +31 -0
- data/docs/general/getting_started.md +133 -0
- data/docs/general/instrumentation.md +40 -0
- data/docs/general/key_transforms.md +40 -0
- data/docs/general/logging.md +21 -0
- data/docs/general/rendering.md +293 -0
- data/docs/general/serializers.md +495 -0
- data/docs/how-open-source-maintained.jpg +0 -0
- data/docs/howto/add_pagination_links.md +138 -0
- data/docs/howto/add_relationship_links.md +140 -0
- data/docs/howto/add_root_key.md +62 -0
- data/docs/howto/grape_integration.md +42 -0
- data/docs/howto/outside_controller_use.md +66 -0
- data/docs/howto/passing_arbitrary_options.md +27 -0
- data/docs/howto/serialize_poro.md +73 -0
- data/docs/howto/test.md +154 -0
- data/docs/howto/upgrade_from_0_8_to_0_10.md +265 -0
- data/docs/integrations/ember-and-json-api.md +147 -0
- data/docs/integrations/grape.md +19 -0
- data/docs/jsonapi/errors.md +56 -0
- data/docs/jsonapi/schema.md +151 -0
- data/docs/jsonapi/schema/schema.json +366 -0
- data/docs/rfcs/0000-namespace.md +106 -0
- data/docs/rfcs/template.md +15 -0
- data/lib/action_controller/serialization.rb +76 -0
- data/lib/active_model/serializable_resource.rb +13 -0
- data/lib/active_model/serializer.rb +418 -0
- data/lib/active_model/serializer/adapter.rb +26 -0
- data/lib/active_model/serializer/adapter/attributes.rb +17 -0
- data/lib/active_model/serializer/adapter/base.rb +20 -0
- data/lib/active_model/serializer/adapter/json.rb +17 -0
- data/lib/active_model/serializer/adapter/json_api.rb +17 -0
- data/lib/active_model/serializer/adapter/null.rb +17 -0
- data/lib/active_model/serializer/array_serializer.rb +14 -0
- data/lib/active_model/serializer/association.rb +91 -0
- data/lib/active_model/serializer/attribute.rb +27 -0
- data/lib/active_model/serializer/belongs_to_reflection.rb +13 -0
- data/lib/active_model/serializer/collection_serializer.rb +90 -0
- data/lib/active_model/serializer/concerns/caching.rb +304 -0
- data/lib/active_model/serializer/error_serializer.rb +16 -0
- data/lib/active_model/serializer/errors_serializer.rb +34 -0
- data/lib/active_model/serializer/field.rb +92 -0
- data/lib/active_model/serializer/fieldset.rb +33 -0
- data/lib/active_model/serializer/has_many_reflection.rb +12 -0
- data/lib/active_model/serializer/has_one_reflection.rb +9 -0
- data/lib/active_model/serializer/lazy_association.rb +99 -0
- data/lib/active_model/serializer/link.rb +23 -0
- data/lib/active_model/serializer/lint.rb +152 -0
- data/lib/active_model/serializer/null.rb +19 -0
- data/lib/active_model/serializer/reflection.rb +212 -0
- data/lib/active_model/serializer/version.rb +7 -0
- data/lib/active_model_serializers.rb +63 -0
- data/lib/active_model_serializers/adapter.rb +100 -0
- data/lib/active_model_serializers/adapter/attributes.rb +15 -0
- data/lib/active_model_serializers/adapter/base.rb +85 -0
- data/lib/active_model_serializers/adapter/json.rb +23 -0
- data/lib/active_model_serializers/adapter/json_api.rb +535 -0
- data/lib/active_model_serializers/adapter/json_api/deserialization.rb +215 -0
- data/lib/active_model_serializers/adapter/json_api/error.rb +98 -0
- data/lib/active_model_serializers/adapter/json_api/jsonapi.rb +51 -0
- data/lib/active_model_serializers/adapter/json_api/link.rb +85 -0
- data/lib/active_model_serializers/adapter/json_api/meta.rb +39 -0
- data/lib/active_model_serializers/adapter/json_api/pagination_links.rb +90 -0
- data/lib/active_model_serializers/adapter/json_api/relationship.rb +106 -0
- data/lib/active_model_serializers/adapter/json_api/resource_identifier.rb +68 -0
- data/lib/active_model_serializers/adapter/null.rb +11 -0
- data/lib/active_model_serializers/callbacks.rb +57 -0
- data/lib/active_model_serializers/deprecate.rb +56 -0
- data/lib/active_model_serializers/deserialization.rb +17 -0
- data/lib/active_model_serializers/json_pointer.rb +16 -0
- data/lib/active_model_serializers/logging.rb +124 -0
- data/lib/active_model_serializers/lookup_chain.rb +82 -0
- data/lib/active_model_serializers/model.rb +132 -0
- data/lib/active_model_serializers/railtie.rb +52 -0
- data/lib/active_model_serializers/register_jsonapi_renderer.rb +80 -0
- data/lib/active_model_serializers/serializable_resource.rb +84 -0
- data/lib/active_model_serializers/serialization_context.rb +41 -0
- data/lib/active_model_serializers/test.rb +9 -0
- data/lib/active_model_serializers/test/schema.rb +140 -0
- data/lib/active_model_serializers/test/serializer.rb +127 -0
- data/lib/generators/rails/USAGE +6 -0
- data/lib/generators/rails/resource_override.rb +12 -0
- data/lib/generators/rails/serializer_generator.rb +38 -0
- data/lib/generators/rails/templates/serializer.rb.erb +8 -0
- data/lib/grape/active_model_serializers.rb +18 -0
- data/lib/grape/formatters/active_model_serializers.rb +34 -0
- data/lib/grape/helpers/active_model_serializers.rb +19 -0
- data/lib/tasks/rubocop.rake +55 -0
- data/test/action_controller/adapter_selector_test.rb +64 -0
- data/test/action_controller/explicit_serializer_test.rb +137 -0
- data/test/action_controller/json/include_test.rb +248 -0
- data/test/action_controller/json_api/deserialization_test.rb +114 -0
- data/test/action_controller/json_api/errors_test.rb +42 -0
- data/test/action_controller/json_api/fields_test.rb +68 -0
- data/test/action_controller/json_api/linked_test.rb +204 -0
- data/test/action_controller/json_api/pagination_test.rb +126 -0
- data/test/action_controller/json_api/transform_test.rb +191 -0
- data/test/action_controller/lookup_proc_test.rb +51 -0
- data/test/action_controller/namespace_lookup_test.rb +239 -0
- data/test/action_controller/serialization_scope_name_test.rb +237 -0
- data/test/action_controller/serialization_test.rb +480 -0
- data/test/active_model_serializers/adapter_for_test.rb +210 -0
- data/test/active_model_serializers/json_pointer_test.rb +24 -0
- data/test/active_model_serializers/logging_test.rb +79 -0
- data/test/active_model_serializers/model_test.rb +144 -0
- data/test/active_model_serializers/railtie_test_isolated.rb +70 -0
- data/test/active_model_serializers/register_jsonapi_renderer_test_isolated.rb +163 -0
- data/test/active_model_serializers/serialization_context_test_isolated.rb +73 -0
- data/test/active_model_serializers/test/schema_test.rb +133 -0
- data/test/active_model_serializers/test/serializer_test.rb +64 -0
- data/test/active_record_test.rb +11 -0
- data/test/adapter/attributes_test.rb +42 -0
- data/test/adapter/deprecation_test.rb +102 -0
- data/test/adapter/json/belongs_to_test.rb +47 -0
- data/test/adapter/json/collection_test.rb +106 -0
- data/test/adapter/json/has_many_test.rb +55 -0
- data/test/adapter/json/transform_test.rb +95 -0
- data/test/adapter/json_api/belongs_to_test.rb +157 -0
- data/test/adapter/json_api/collection_test.rb +98 -0
- data/test/adapter/json_api/errors_test.rb +78 -0
- data/test/adapter/json_api/fields_test.rb +98 -0
- data/test/adapter/json_api/has_many_explicit_serializer_test.rb +98 -0
- data/test/adapter/json_api/has_many_test.rb +175 -0
- data/test/adapter/json_api/has_one_test.rb +82 -0
- data/test/adapter/json_api/include_data_if_sideloaded_test.rb +215 -0
- data/test/adapter/json_api/json_api_test.rb +35 -0
- data/test/adapter/json_api/linked_test.rb +415 -0
- data/test/adapter/json_api/links_test.rb +112 -0
- data/test/adapter/json_api/pagination_links_test.rb +208 -0
- data/test/adapter/json_api/parse_test.rb +139 -0
- data/test/adapter/json_api/relationship_test.rb +399 -0
- data/test/adapter/json_api/resource_meta_test.rb +102 -0
- data/test/adapter/json_api/toplevel_jsonapi_test.rb +84 -0
- data/test/adapter/json_api/transform_test.rb +514 -0
- data/test/adapter/json_api/type_test.rb +195 -0
- data/test/adapter/json_test.rb +48 -0
- data/test/adapter/null_test.rb +24 -0
- data/test/adapter/polymorphic_test.rb +220 -0
- data/test/adapter_test.rb +69 -0
- data/test/array_serializer_test.rb +24 -0
- data/test/benchmark/app.rb +67 -0
- data/test/benchmark/benchmarking_support.rb +69 -0
- data/test/benchmark/bm_active_record.rb +83 -0
- data/test/benchmark/bm_adapter.rb +40 -0
- data/test/benchmark/bm_caching.rb +121 -0
- data/test/benchmark/bm_lookup_chain.rb +85 -0
- data/test/benchmark/bm_transform.rb +47 -0
- data/test/benchmark/config.ru +3 -0
- data/test/benchmark/controllers.rb +85 -0
- data/test/benchmark/fixtures.rb +221 -0
- data/test/cache_test.rb +717 -0
- data/test/collection_serializer_test.rb +129 -0
- data/test/fixtures/active_record.rb +115 -0
- data/test/fixtures/poro.rb +227 -0
- data/test/generators/scaffold_controller_generator_test.rb +26 -0
- data/test/generators/serializer_generator_test.rb +77 -0
- data/test/grape_test.rb +198 -0
- data/test/lint_test.rb +51 -0
- data/test/logger_test.rb +22 -0
- data/test/poro_test.rb +11 -0
- data/test/serializable_resource_test.rb +81 -0
- data/test/serializers/association_macros_test.rb +39 -0
- data/test/serializers/associations_test.rb +520 -0
- data/test/serializers/attribute_test.rb +155 -0
- data/test/serializers/attributes_test.rb +54 -0
- data/test/serializers/caching_configuration_test_isolated.rb +172 -0
- data/test/serializers/configuration_test.rb +34 -0
- data/test/serializers/fieldset_test.rb +16 -0
- data/test/serializers/meta_test.rb +204 -0
- data/test/serializers/options_test.rb +34 -0
- data/test/serializers/read_attribute_for_serialization_test.rb +81 -0
- data/test/serializers/reflection_test.rb +481 -0
- data/test/serializers/root_test.rb +23 -0
- data/test/serializers/serialization_test.rb +57 -0
- data/test/serializers/serializer_for_test.rb +138 -0
- data/test/serializers/serializer_for_with_namespace_test.rb +90 -0
- data/test/support/custom_schemas/active_model_serializers/test/schema_test/my/index.json +6 -0
- data/test/support/isolated_unit.rb +86 -0
- data/test/support/rails5_shims.rb +55 -0
- data/test/support/rails_app.rb +40 -0
- data/test/support/schemas/active_model_serializers/test/schema_test/my/index.json +6 -0
- data/test/support/schemas/active_model_serializers/test/schema_test/my/show.json +6 -0
- data/test/support/schemas/custom/show.json +7 -0
- data/test/support/schemas/hyper_schema.json +93 -0
- data/test/support/schemas/render_using_json_api.json +43 -0
- data/test/support/schemas/simple_json_pointers.json +10 -0
- data/test/support/serialization_testing.rb +81 -0
- data/test/test_helper.rb +72 -0
- metadata +622 -0
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'set'
|
|
4
|
+
|
|
5
|
+
module ActiveModelSerializers
|
|
6
|
+
class SerializableResource
|
|
7
|
+
ADAPTER_OPTION_KEYS = Set.new([:include, :fields, :adapter, :meta, :meta_key, :links, :serialization_context, :key_transform])
|
|
8
|
+
include ActiveModelSerializers::Logging
|
|
9
|
+
|
|
10
|
+
delegate :serializable_hash, :as_json, :to_json, to: :adapter
|
|
11
|
+
notify :serializable_hash, :render
|
|
12
|
+
notify :as_json, :render
|
|
13
|
+
notify :to_json, :render
|
|
14
|
+
|
|
15
|
+
# Primary interface to composing a resource with a serializer and adapter.
|
|
16
|
+
# @return the serializable_resource, ready for #as_json/#to_json/#serializable_hash.
|
|
17
|
+
def initialize(resource, options = {})
|
|
18
|
+
@resource = resource
|
|
19
|
+
@adapter_opts = options.select { |k, _| ADAPTER_OPTION_KEYS.include? k }
|
|
20
|
+
@serializer_opts = options.reject { |k, _| ADAPTER_OPTION_KEYS.include? k }
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def serialization_scope=(scope)
|
|
24
|
+
serializer_opts[:scope] = scope
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def serialization_scope
|
|
28
|
+
serializer_opts[:scope]
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def serialization_scope_name=(scope_name)
|
|
32
|
+
serializer_opts[:scope_name] = scope_name
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# NOTE: if no adapter is available, returns the resource itself. (i.e. adapter is a no-op)
|
|
36
|
+
def adapter
|
|
37
|
+
@adapter ||= find_adapter
|
|
38
|
+
end
|
|
39
|
+
alias adapter_instance adapter
|
|
40
|
+
|
|
41
|
+
def find_adapter
|
|
42
|
+
return resource unless serializer?
|
|
43
|
+
adapter = catch :no_serializer do
|
|
44
|
+
ActiveModelSerializers::Adapter.create(serializer_instance, adapter_opts)
|
|
45
|
+
end
|
|
46
|
+
adapter || resource
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def serializer_instance
|
|
50
|
+
@serializer_instance ||= serializer.new(resource, serializer_opts)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Get serializer either explicitly :serializer or implicitly from resource
|
|
54
|
+
# Remove :serializer key from serializer_opts
|
|
55
|
+
# Remove :each_serializer if present and set as :serializer key
|
|
56
|
+
def serializer
|
|
57
|
+
@serializer ||=
|
|
58
|
+
begin
|
|
59
|
+
@serializer = serializer_opts.delete(:serializer)
|
|
60
|
+
@serializer ||= ActiveModel::Serializer.serializer_for(resource, serializer_opts)
|
|
61
|
+
|
|
62
|
+
if serializer_opts.key?(:each_serializer)
|
|
63
|
+
serializer_opts[:serializer] = serializer_opts.delete(:each_serializer)
|
|
64
|
+
end
|
|
65
|
+
@serializer
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
alias serializer_class serializer
|
|
69
|
+
|
|
70
|
+
# True when no explicit adapter given, or explicit appear is truthy (non-nil)
|
|
71
|
+
# False when explicit adapter is falsy (nil or false)
|
|
72
|
+
def use_adapter?
|
|
73
|
+
!(adapter_opts.key?(:adapter) && !adapter_opts[:adapter])
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def serializer?
|
|
77
|
+
use_adapter? && !serializer.nil?
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
protected
|
|
81
|
+
|
|
82
|
+
attr_reader :resource, :adapter_opts, :serializer_opts
|
|
83
|
+
end
|
|
84
|
+
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'active_support/core_ext/array/extract_options'
|
|
4
|
+
module ActiveModelSerializers
|
|
5
|
+
class SerializationContext
|
|
6
|
+
class << self
|
|
7
|
+
attr_writer :url_helpers, :default_url_options
|
|
8
|
+
def url_helpers
|
|
9
|
+
@url_helpers ||= Module.new
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def default_url_options
|
|
13
|
+
@default_url_options ||= {}
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
module UrlHelpers
|
|
17
|
+
def self.included(base)
|
|
18
|
+
base.send(:include, SerializationContext.url_helpers)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def default_url_options
|
|
22
|
+
SerializationContext.default_url_options
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
attr_reader :request_url, :query_parameters, :key_transform
|
|
27
|
+
|
|
28
|
+
def initialize(*args)
|
|
29
|
+
options = args.extract_options!
|
|
30
|
+
if args.size == 1
|
|
31
|
+
request = args.pop
|
|
32
|
+
options[:request_url] = request.original_url[/\A[^?]+/]
|
|
33
|
+
options[:query_parameters] = request.query_parameters
|
|
34
|
+
end
|
|
35
|
+
@request_url = options.delete(:request_url)
|
|
36
|
+
@query_parameters = options.delete(:query_parameters)
|
|
37
|
+
@url_helpers = options.delete(:url_helpers) || self.class.url_helpers
|
|
38
|
+
@default_url_options = options.delete(:default_url_options) || self.class.default_url_options
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ActiveModelSerializers
|
|
4
|
+
module Test
|
|
5
|
+
module Schema
|
|
6
|
+
# A Minitest Assertion that test the response is valid against a schema.
|
|
7
|
+
# @param schema_path [String] a custom schema path
|
|
8
|
+
# @param message [String] a custom error message
|
|
9
|
+
# @return [Boolean] true when the response is valid
|
|
10
|
+
# @return [Minitest::Assertion] when the response is invalid
|
|
11
|
+
# @example
|
|
12
|
+
# get :index
|
|
13
|
+
# assert_response_schema
|
|
14
|
+
def assert_response_schema(schema_path = nil, message = nil)
|
|
15
|
+
matcher = AssertResponseSchema.new(schema_path, request, response, message)
|
|
16
|
+
assert(matcher.call, matcher.message)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def assert_request_schema(schema_path = nil, message = nil)
|
|
20
|
+
matcher = AssertRequestSchema.new(schema_path, request, response, message)
|
|
21
|
+
assert(matcher.call, matcher.message)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# May be renamed
|
|
25
|
+
def assert_request_response_schema(schema_path = nil, message = nil)
|
|
26
|
+
assert_request_schema(schema_path, message)
|
|
27
|
+
assert_response_schema(schema_path, message)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def assert_schema(payload, schema_path = nil, message = nil)
|
|
31
|
+
matcher = AssertSchema.new(schema_path, request, response, message, payload)
|
|
32
|
+
assert(matcher.call, matcher.message)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
MissingSchema = Class.new(Minitest::Assertion)
|
|
36
|
+
InvalidSchemaError = Class.new(Minitest::Assertion)
|
|
37
|
+
|
|
38
|
+
class AssertSchema
|
|
39
|
+
attr_reader :schema_path, :request, :response, :message, :payload
|
|
40
|
+
|
|
41
|
+
# Interface may change.
|
|
42
|
+
def initialize(schema_path, request, response, message, payload = nil)
|
|
43
|
+
require_json_schema!
|
|
44
|
+
@request = request
|
|
45
|
+
@response = response
|
|
46
|
+
@payload = payload
|
|
47
|
+
@schema_path = schema_path || schema_path_default
|
|
48
|
+
@message = message
|
|
49
|
+
@document_store = JsonSchema::DocumentStore.new
|
|
50
|
+
add_schema_to_document_store
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def call
|
|
54
|
+
json_schema.expand_references!(store: document_store)
|
|
55
|
+
status, errors = json_schema.validate(response_body)
|
|
56
|
+
@message = [message, errors.map(&:to_s).to_sentence].compact.join(': ')
|
|
57
|
+
status
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
protected
|
|
61
|
+
|
|
62
|
+
attr_reader :document_store
|
|
63
|
+
|
|
64
|
+
def controller_path
|
|
65
|
+
request.filtered_parameters.with_indifferent_access[:controller]
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def action
|
|
69
|
+
request.filtered_parameters.with_indifferent_access[:action]
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def schema_directory
|
|
73
|
+
ActiveModelSerializers.config.schema_path
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def schema_full_path
|
|
77
|
+
"#{schema_directory}/#{schema_path}"
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def schema_path_default
|
|
81
|
+
"#{controller_path}/#{action}.json"
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def schema_data
|
|
85
|
+
load_json_file(schema_full_path)
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def response_body
|
|
89
|
+
load_json(response.body)
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def request_params
|
|
93
|
+
request.env['action_dispatch.request.request_parameters']
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def json_schema
|
|
97
|
+
@json_schema ||= JsonSchema.parse!(schema_data)
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def add_schema_to_document_store
|
|
101
|
+
Dir.glob("#{schema_directory}/**/*.json").each do |path|
|
|
102
|
+
schema_data = load_json_file(path)
|
|
103
|
+
extra_schema = JsonSchema.parse!(schema_data)
|
|
104
|
+
document_store.add_schema(extra_schema)
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def load_json(json)
|
|
109
|
+
JSON.parse(json)
|
|
110
|
+
rescue JSON::ParserError => ex
|
|
111
|
+
raise InvalidSchemaError, ex.message
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def load_json_file(path)
|
|
115
|
+
load_json(File.read(path))
|
|
116
|
+
rescue Errno::ENOENT
|
|
117
|
+
raise MissingSchema, "No Schema file at #{schema_full_path}"
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def require_json_schema!
|
|
121
|
+
require 'json_schema'
|
|
122
|
+
rescue LoadError
|
|
123
|
+
raise LoadError, "You don't have json_schema installed in your application. Please add it to your Gemfile and run bundle install"
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
class AssertResponseSchema < AssertSchema
|
|
127
|
+
def initialize(*)
|
|
128
|
+
super
|
|
129
|
+
@payload = response_body
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
class AssertRequestSchema < AssertSchema
|
|
133
|
+
def initialize(*)
|
|
134
|
+
super
|
|
135
|
+
@payload = request_params
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
end
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'set'
|
|
4
|
+
module ActiveModelSerializers
|
|
5
|
+
module Test
|
|
6
|
+
module Serializer
|
|
7
|
+
extend ActiveSupport::Concern
|
|
8
|
+
|
|
9
|
+
included do
|
|
10
|
+
setup :setup_serialization_subscriptions
|
|
11
|
+
teardown :teardown_serialization_subscriptions
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# Asserts that the request was rendered with the appropriate serializers.
|
|
15
|
+
#
|
|
16
|
+
# # assert that the "PostSerializer" serializer was rendered
|
|
17
|
+
# assert_serializer "PostSerializer"
|
|
18
|
+
#
|
|
19
|
+
# # return a custom error message
|
|
20
|
+
# assert_serializer "PostSerializer", "PostSerializer not rendered"
|
|
21
|
+
#
|
|
22
|
+
# # assert that the instance of PostSerializer was rendered
|
|
23
|
+
# assert_serializer PostSerializer
|
|
24
|
+
#
|
|
25
|
+
# # assert that the "PostSerializer" serializer was rendered
|
|
26
|
+
# assert_serializer :post_serializer
|
|
27
|
+
#
|
|
28
|
+
# # assert that the rendered serializer starts with "Post"
|
|
29
|
+
# assert_serializer %r{\APost.+\Z}
|
|
30
|
+
#
|
|
31
|
+
# # assert that no serializer was rendered
|
|
32
|
+
# assert_serializer nil
|
|
33
|
+
#
|
|
34
|
+
def assert_serializer(expectation, message = nil)
|
|
35
|
+
@assert_serializer.expectation = expectation
|
|
36
|
+
@assert_serializer.message = message
|
|
37
|
+
@assert_serializer.response = response
|
|
38
|
+
assert(@assert_serializer.matches?, @assert_serializer.message)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
class AssertSerializer
|
|
42
|
+
attr_reader :serializers, :message
|
|
43
|
+
attr_accessor :response, :expectation
|
|
44
|
+
|
|
45
|
+
def initialize
|
|
46
|
+
@serializers = Set.new
|
|
47
|
+
@_subscribers = []
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def message=(message)
|
|
51
|
+
@message = message || "expecting <#{expectation.inspect}> but rendering with <#{serializers.to_a}>"
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def matches?
|
|
55
|
+
# Force body to be read in case the template is being streamed.
|
|
56
|
+
response.body
|
|
57
|
+
|
|
58
|
+
case expectation
|
|
59
|
+
when a_serializer? then matches_class?
|
|
60
|
+
when Symbol then matches_symbol?
|
|
61
|
+
when String then matches_string?
|
|
62
|
+
when Regexp then matches_regexp?
|
|
63
|
+
when NilClass then matches_nil?
|
|
64
|
+
else fail ArgumentError, 'assert_serializer only accepts a String, Symbol, Regexp, ActiveModel::Serializer, or nil'
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def subscribe
|
|
69
|
+
@_subscribers << ActiveSupport::Notifications.subscribe(event_name) do |_name, _start, _finish, _id, payload|
|
|
70
|
+
serializer = payload[:serializer].name
|
|
71
|
+
serializers << serializer
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def unsubscribe
|
|
76
|
+
@_subscribers.each do |subscriber|
|
|
77
|
+
ActiveSupport::Notifications.unsubscribe(subscriber)
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
private
|
|
82
|
+
|
|
83
|
+
def matches_class?
|
|
84
|
+
serializers.include?(expectation.name)
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def matches_symbol?
|
|
88
|
+
camelize_expectation = expectation.to_s.camelize
|
|
89
|
+
serializers.include?(camelize_expectation)
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def matches_string?
|
|
93
|
+
!expectation.empty? && serializers.include?(expectation)
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def matches_regexp?
|
|
97
|
+
serializers.any? do |serializer|
|
|
98
|
+
serializer.match(expectation)
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def matches_nil?
|
|
103
|
+
serializers.empty?
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def a_serializer?
|
|
107
|
+
->(exp) { exp.is_a?(Class) && exp < ActiveModel::Serializer }
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def event_name
|
|
111
|
+
::ActiveModelSerializers::Logging::RENDER_EVENT
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
private
|
|
116
|
+
|
|
117
|
+
def setup_serialization_subscriptions
|
|
118
|
+
@assert_serializer = AssertSerializer.new
|
|
119
|
+
@assert_serializer.subscribe
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
def teardown_serialization_subscriptions
|
|
123
|
+
@assert_serializer.unsubscribe
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
end
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'rails/generators'
|
|
4
|
+
require 'rails/generators/rails/resource/resource_generator'
|
|
5
|
+
|
|
6
|
+
module Rails
|
|
7
|
+
module Generators
|
|
8
|
+
class ResourceGenerator
|
|
9
|
+
hook_for :serializer, default: true, type: :boolean
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Rails
|
|
4
|
+
module Generators
|
|
5
|
+
class SerializerGenerator < NamedBase
|
|
6
|
+
source_root File.expand_path('../templates', __FILE__)
|
|
7
|
+
check_class_collision suffix: 'Serializer'
|
|
8
|
+
|
|
9
|
+
argument :attributes, type: :array, default: [], banner: 'field:type field:type'
|
|
10
|
+
|
|
11
|
+
class_option :parent, type: :string, desc: 'The parent class for the generated serializer'
|
|
12
|
+
|
|
13
|
+
def create_serializer_file
|
|
14
|
+
template 'serializer.rb.erb', File.join('app/serializers', class_path, "#{file_name}_serializer.rb")
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
private
|
|
18
|
+
|
|
19
|
+
def attributes_names
|
|
20
|
+
[:id] + attributes.reject(&:reference?).map! { |a| a.name.to_sym }
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def association_names
|
|
24
|
+
attributes.select(&:reference?).map! { |a| a.name.to_sym }
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def parent_class_name
|
|
28
|
+
if options[:parent]
|
|
29
|
+
options[:parent]
|
|
30
|
+
elsif 'ApplicationSerializer'.safe_constantize
|
|
31
|
+
'ApplicationSerializer'
|
|
32
|
+
else
|
|
33
|
+
'ActiveModel::Serializer'
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|