active_model_serializers 0.8.3 → 0.10.0.rc4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (184) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +6 -0
  3. data/.rubocop.yml +86 -0
  4. data/.rubocop_todo.yml +240 -0
  5. data/.simplecov +111 -0
  6. data/.travis.yml +33 -22
  7. data/CHANGELOG.md +358 -6
  8. data/CONTRIBUTING.md +220 -0
  9. data/Gemfile +46 -1
  10. data/{MIT-LICENSE.txt → LICENSE.txt} +3 -2
  11. data/README.md +81 -591
  12. data/Rakefile +68 -11
  13. data/active_model_serializers.gemspec +57 -23
  14. data/appveyor.yml +27 -0
  15. data/docs/ARCHITECTURE.md +120 -0
  16. data/docs/DESIGN.textile +8 -0
  17. data/docs/README.md +35 -0
  18. data/docs/general/adapters.md +162 -0
  19. data/docs/general/caching.md +52 -0
  20. data/docs/general/configuration_options.md +27 -0
  21. data/docs/general/getting_started.md +98 -0
  22. data/docs/general/instrumentation.md +40 -0
  23. data/docs/general/logging.md +14 -0
  24. data/docs/general/rendering.md +153 -0
  25. data/docs/general/serializers.md +207 -0
  26. data/docs/how-open-source-maintained.jpg +0 -0
  27. data/docs/howto/add_pagination_links.md +121 -0
  28. data/docs/howto/add_root_key.md +51 -0
  29. data/docs/howto/outside_controller_use.md +58 -0
  30. data/docs/howto/test.md +152 -0
  31. data/docs/integrations/ember-and-json-api.md +112 -0
  32. data/docs/integrations/grape.md +19 -0
  33. data/docs/jsonapi/schema/schema.json +366 -0
  34. data/docs/jsonapi/schema.md +140 -0
  35. data/lib/action_controller/serialization.rb +41 -37
  36. data/lib/active_model/serializable_resource.rb +72 -0
  37. data/lib/active_model/serializer/adapter/attributes.rb +66 -0
  38. data/lib/active_model/serializer/adapter/base.rb +58 -0
  39. data/lib/active_model/serializer/adapter/cached_serializer.rb +45 -0
  40. data/lib/active_model/serializer/adapter/fragment_cache.rb +111 -0
  41. data/lib/active_model/serializer/adapter/json/fragment_cache.rb +13 -0
  42. data/lib/active_model/serializer/adapter/json.rb +21 -0
  43. data/lib/active_model/serializer/adapter/json_api/deserialization.rb +207 -0
  44. data/lib/active_model/serializer/adapter/json_api/fragment_cache.rb +21 -0
  45. data/lib/active_model/serializer/adapter/json_api/link.rb +44 -0
  46. data/lib/active_model/serializer/adapter/json_api/pagination_links.rb +58 -0
  47. data/lib/active_model/serializer/adapter/json_api.rb +223 -0
  48. data/lib/active_model/serializer/adapter/null.rb +11 -0
  49. data/lib/active_model/serializer/adapter.rb +91 -0
  50. data/lib/active_model/serializer/array_serializer.rb +9 -0
  51. data/lib/active_model/serializer/association.rb +20 -0
  52. data/lib/active_model/serializer/associations.rb +87 -220
  53. data/lib/active_model/serializer/attribute.rb +25 -0
  54. data/lib/active_model/serializer/attributes.rb +82 -0
  55. data/lib/active_model/serializer/belongs_to_reflection.rb +10 -0
  56. data/lib/active_model/serializer/caching.rb +100 -0
  57. data/lib/active_model/serializer/collection_reflection.rb +7 -0
  58. data/lib/active_model/serializer/collection_serializer.rb +47 -0
  59. data/lib/active_model/serializer/configuration.rb +28 -0
  60. data/lib/active_model/serializer/field.rb +56 -0
  61. data/lib/active_model/serializer/fieldset.rb +31 -0
  62. data/lib/active_model/serializer/has_many_reflection.rb +10 -0
  63. data/lib/active_model/serializer/has_one_reflection.rb +10 -0
  64. data/lib/active_model/serializer/include_tree.rb +111 -0
  65. data/lib/active_model/serializer/links.rb +33 -0
  66. data/lib/active_model/serializer/lint.rb +142 -0
  67. data/lib/active_model/serializer/reflection.rb +91 -0
  68. data/lib/active_model/serializer/singular_reflection.rb +7 -0
  69. data/lib/active_model/serializer/type.rb +25 -0
  70. data/lib/active_model/{serializers → serializer}/version.rb +1 -1
  71. data/lib/active_model/serializer.rb +99 -479
  72. data/lib/active_model_serializers/callbacks.rb +55 -0
  73. data/lib/active_model_serializers/deserialization.rb +13 -0
  74. data/lib/active_model_serializers/logging.rb +119 -0
  75. data/lib/active_model_serializers/model.rb +39 -0
  76. data/lib/active_model_serializers/railtie.rb +38 -0
  77. data/lib/active_model_serializers/serialization_context.rb +10 -0
  78. data/lib/active_model_serializers/test/schema.rb +103 -0
  79. data/lib/active_model_serializers/test/serializer.rb +125 -0
  80. data/lib/active_model_serializers/test.rb +7 -0
  81. data/lib/active_model_serializers.rb +20 -92
  82. data/lib/generators/rails/USAGE +6 -0
  83. data/lib/generators/rails/resource_override.rb +10 -0
  84. data/lib/generators/rails/serializer_generator.rb +36 -0
  85. data/lib/generators/rails/templates/serializer.rb.erb +8 -0
  86. data/lib/grape/active_model_serializers.rb +14 -0
  87. data/lib/grape/formatters/active_model_serializers.rb +15 -0
  88. data/lib/grape/helpers/active_model_serializers.rb +16 -0
  89. data/test/action_controller/adapter_selector_test.rb +53 -0
  90. data/test/action_controller/explicit_serializer_test.rb +134 -0
  91. data/test/action_controller/json/include_test.rb +167 -0
  92. data/test/action_controller/json_api/deserialization_test.rb +59 -0
  93. data/test/action_controller/json_api/linked_test.rb +196 -0
  94. data/test/action_controller/json_api/pagination_test.rb +116 -0
  95. data/test/{serialization_scope_name_test.rb → action_controller/serialization_scope_name_test.rb} +11 -15
  96. data/test/action_controller/serialization_test.rb +435 -0
  97. data/test/active_model_serializers/logging_test.rb +77 -0
  98. data/test/active_model_serializers/model_test.rb +9 -0
  99. data/test/active_model_serializers/railtie_test_isolated.rb +57 -0
  100. data/test/active_model_serializers/serialization_context_test.rb +18 -0
  101. data/test/active_model_serializers/test/schema_test.rb +128 -0
  102. data/test/active_model_serializers/test/serializer_test.rb +63 -0
  103. data/test/active_record_test.rb +9 -0
  104. data/test/adapter/fragment_cache_test.rb +38 -0
  105. data/test/adapter/json/belongs_to_test.rb +47 -0
  106. data/test/adapter/json/collection_test.rb +92 -0
  107. data/test/adapter/json/has_many_test.rb +47 -0
  108. data/test/adapter/json_api/belongs_to_test.rb +157 -0
  109. data/test/adapter/json_api/collection_test.rb +97 -0
  110. data/test/adapter/json_api/fields_test.rb +89 -0
  111. data/test/adapter/json_api/has_many_embed_ids_test.rb +45 -0
  112. data/test/adapter/json_api/has_many_explicit_serializer_test.rb +98 -0
  113. data/test/adapter/json_api/has_many_test.rb +145 -0
  114. data/test/adapter/json_api/has_one_test.rb +81 -0
  115. data/test/adapter/json_api/json_api_test.rb +37 -0
  116. data/test/adapter/json_api/linked_test.rb +394 -0
  117. data/test/adapter/json_api/links_test.rb +68 -0
  118. data/test/adapter/json_api/pagination_links_test.rb +115 -0
  119. data/test/adapter/json_api/parse_test.rb +139 -0
  120. data/test/adapter/json_api/resource_type_config_test.rb +71 -0
  121. data/test/adapter/json_api/toplevel_jsonapi_test.rb +84 -0
  122. data/test/adapter/json_test.rb +47 -0
  123. data/test/adapter/null_test.rb +25 -0
  124. data/test/adapter_test.rb +42 -0
  125. data/test/array_serializer_test.rb +36 -73
  126. data/test/collection_serializer_test.rb +100 -0
  127. data/test/fixtures/active_record.rb +56 -0
  128. data/test/fixtures/poro.rb +229 -0
  129. data/test/generators/scaffold_controller_generator_test.rb +24 -0
  130. data/test/generators/serializer_generator_test.rb +57 -0
  131. data/test/grape_test.rb +82 -0
  132. data/test/include_tree/from_include_args_test.rb +26 -0
  133. data/test/include_tree/from_string_test.rb +94 -0
  134. data/test/include_tree/include_args_to_hash_test.rb +64 -0
  135. data/test/lint_test.rb +40 -0
  136. data/test/logger_test.rb +18 -0
  137. data/test/poro_test.rb +9 -0
  138. data/test/serializable_resource_test.rb +27 -0
  139. data/test/serializers/adapter_for_test.rb +166 -0
  140. data/test/serializers/association_macros_test.rb +36 -0
  141. data/test/serializers/associations_test.rb +267 -0
  142. data/test/serializers/attribute_test.rb +123 -0
  143. data/test/serializers/attributes_test.rb +52 -0
  144. data/test/serializers/cache_test.rb +209 -0
  145. data/test/serializers/configuration_test.rb +32 -0
  146. data/test/serializers/fieldset_test.rb +14 -0
  147. data/test/serializers/meta_test.rb +130 -0
  148. data/test/serializers/options_test.rb +21 -0
  149. data/test/serializers/root_test.rb +21 -0
  150. data/test/serializers/serializer_for_test.rb +134 -0
  151. data/test/support/custom_schemas/active_model_serializers/test/schema_test/my/index.json +6 -0
  152. data/test/support/isolated_unit.rb +77 -0
  153. data/test/support/rails5_shims.rb +29 -0
  154. data/test/support/rails_app.rb +25 -0
  155. data/test/support/schemas/active_model_serializers/test/schema_test/my/index.json +6 -0
  156. data/test/support/schemas/active_model_serializers/test/schema_test/my/show.json +6 -0
  157. data/test/support/schemas/custom/show.json +7 -0
  158. data/test/support/schemas/hyper_schema.json +93 -0
  159. data/test/support/schemas/render_using_json_api.json +43 -0
  160. data/test/support/schemas/simple_json_pointers.json +10 -0
  161. data/test/support/serialization_testing.rb +53 -0
  162. data/test/support/simplecov.rb +6 -0
  163. data/test/support/stream_capture.rb +50 -0
  164. data/test/support/test_case.rb +19 -0
  165. data/test/test_helper.rb +55 -24
  166. metadata +358 -42
  167. data/DESIGN.textile +0 -586
  168. data/Gemfile.edge +0 -9
  169. data/bench/perf.rb +0 -43
  170. data/cruft.md +0 -19
  171. data/lib/active_model/array_serializer.rb +0 -104
  172. data/lib/active_record/serializer_override.rb +0 -16
  173. data/lib/generators/resource_override.rb +0 -13
  174. data/lib/generators/serializer/USAGE +0 -9
  175. data/lib/generators/serializer/serializer_generator.rb +0 -42
  176. data/lib/generators/serializer/templates/serializer.rb +0 -19
  177. data/test/association_test.rb +0 -592
  178. data/test/caching_test.rb +0 -96
  179. data/test/generators_test.rb +0 -85
  180. data/test/no_serialization_scope_test.rb +0 -34
  181. data/test/serialization_test.rb +0 -392
  182. data/test/serializer_support_test.rb +0 -51
  183. data/test/serializer_test.rb +0 -1465
  184. data/test/test_fakes.rb +0 -217
@@ -0,0 +1,119 @@
1
+ ##
2
+ # ActiveModelSerializers::Logging
3
+ #
4
+ # https://github.com/rails/rails/blob/280654ef88/activejob/lib/active_job/logging.rb
5
+ #
6
+ module ActiveModelSerializers
7
+ module Logging
8
+ RENDER_EVENT = 'render.active_model_serializers'.freeze
9
+ extend ActiveSupport::Concern
10
+
11
+ included do
12
+ include ActiveModelSerializers::Callbacks
13
+ extend Macros
14
+ instrument_rendering
15
+ end
16
+
17
+ module ClassMethods
18
+ def instrument_rendering
19
+ around_render do |args, block|
20
+ tag_logger do
21
+ notify_render do
22
+ block.call(args)
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
28
+
29
+ # Macros that can be used to customize the logging of class or instance methods,
30
+ # by extending the class or its singleton.
31
+ #
32
+ # Adapted from:
33
+ # https://github.com/rubygems/rubygems/blob/cb28f5e991/lib/rubygems/deprecate.rb
34
+ #
35
+ # Provides a single method +notify+ to be used to declare when
36
+ # something a method notifies, with the argument +callback_name+ of the notification callback.
37
+ #
38
+ # class Adapter
39
+ # def self.klass_method
40
+ # # ...
41
+ # end
42
+ #
43
+ # def instance_method
44
+ # # ...
45
+ # end
46
+ #
47
+ # include ActiveModelSerializers::Logging::Macros
48
+ # notify :instance_method, :render
49
+ #
50
+ # class << self
51
+ # extend ActiveModelSerializers::Logging::Macros
52
+ # notify :klass_method, :render
53
+ # end
54
+ # end
55
+ module Macros
56
+ ##
57
+ # Simple notify method that wraps up +name+
58
+ # in a dummy method. It notifies on with the +callback_name+ notifier on
59
+ # each call to the dummy method, telling what the current serializer and adapter
60
+ # are being rendered.
61
+ # Adapted from:
62
+ # https://github.com/rubygems/rubygems/blob/cb28f5e991/lib/rubygems/deprecate.rb
63
+ def notify(name, callback_name)
64
+ class_eval do
65
+ old = "_notifying_#{callback_name}_#{name}"
66
+ alias_method old, name
67
+ define_method name do |*args, &block|
68
+ run_callbacks callback_name do
69
+ send old, *args, &block
70
+ end
71
+ end
72
+ end
73
+ end
74
+ end
75
+
76
+ def notify_render(*)
77
+ event_name = RENDER_EVENT
78
+ ActiveSupport::Notifications.instrument(event_name, notify_render_payload) do
79
+ yield
80
+ end
81
+ end
82
+
83
+ def notify_render_payload
84
+ { serializer: serializer, adapter: adapter }
85
+ end
86
+
87
+ private
88
+
89
+ def tag_logger(*tags)
90
+ if ActiveModelSerializers.logger.respond_to?(:tagged)
91
+ tags.unshift 'active_model_serializers'.freeze unless logger_tagged_by_active_model_serializers?
92
+ ActiveModelSerializers.logger.tagged(*tags) { yield }
93
+ else
94
+ yield
95
+ end
96
+ end
97
+
98
+ def logger_tagged_by_active_model_serializers?
99
+ ActiveModelSerializers.logger.formatter.current_tags.include?('active_model_serializers'.freeze)
100
+ end
101
+
102
+ class LogSubscriber < ActiveSupport::LogSubscriber
103
+ def render(event)
104
+ info do
105
+ serializer = event.payload[:serializer]
106
+ adapter = event.payload[:adapter]
107
+ duration = event.duration.round(2)
108
+ "Rendered #{serializer.name} with #{adapter.class} (#{duration}ms)"
109
+ end
110
+ end
111
+
112
+ def logger
113
+ ActiveModelSerializers.logger
114
+ end
115
+ end
116
+ end
117
+ end
118
+
119
+ ActiveModelSerializers::Logging::LogSubscriber.attach_to :active_model_serializers
@@ -0,0 +1,39 @@
1
+ # ActiveModelSerializers::Model is a convenient
2
+ # serializable class to inherit from when making
3
+ # serializable non-activerecord objects.
4
+ module ActiveModelSerializers
5
+ class Model
6
+ include ActiveModel::Model
7
+ include ActiveModel::Serializers::JSON
8
+
9
+ attr_reader :attributes
10
+
11
+ def initialize(attributes = {})
12
+ @attributes = attributes
13
+ super
14
+ end
15
+
16
+ # Defaults to the downcased model name.
17
+ def id
18
+ attributes.fetch(:id) { self.class.name.downcase }
19
+ end
20
+
21
+ # Defaults to the downcased model name and updated_at
22
+ def cache_key
23
+ attributes.fetch(:cache_key) { "#{self.class.name.downcase}/#{id}-#{updated_at.strftime("%Y%m%d%H%M%S%9N")}" }
24
+ end
25
+
26
+ # Defaults to the time the serializer file was modified.
27
+ def updated_at
28
+ attributes.fetch(:updated_at) { File.mtime(__FILE__) }
29
+ end
30
+
31
+ def read_attribute_for_serialization(key)
32
+ if key == :id || key == 'id'
33
+ attributes.fetch(key) { id }
34
+ else
35
+ attributes[key]
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,38 @@
1
+ require 'rails/railtie'
2
+ require 'action_controller'
3
+ require 'action_controller/railtie'
4
+ require 'action_controller/serialization'
5
+
6
+ module ActiveModelSerializers
7
+ class Railtie < Rails::Railtie
8
+ config.to_prepare do
9
+ ActiveModel::Serializer.serializers_cache.clear
10
+ end
11
+
12
+ initializer 'active_model_serializers.action_controller' do
13
+ ActiveSupport.on_load(:action_controller) do
14
+ include(::ActionController::Serialization)
15
+ end
16
+ end
17
+
18
+ # This hook is run after the action_controller railtie has set the configuration
19
+ # based on the *environment* configuration and before any config/initializers are run
20
+ # and also before eager_loading (if enabled).
21
+ initializer 'active_model_serializers.set_configs', :after => 'action_controller.set_configs' do
22
+ ActiveModelSerializers.logger = Rails.configuration.action_controller.logger
23
+ ActiveModelSerializers.config.cache_store = Rails.configuration.action_controller.cache_store
24
+ ActiveModelSerializers.config.perform_caching = Rails.configuration.action_controller.perform_caching
25
+ end
26
+
27
+ generators do |app|
28
+ Rails::Generators.configure!(app.config.generators)
29
+ Rails::Generators.hidden_namespaces.uniq!
30
+ require 'generators/rails/resource_override'
31
+ end
32
+
33
+ if Rails.env.test?
34
+ ActionController::TestCase.send(:include, ActiveModelSerializers::Test::Schema)
35
+ ActionController::TestCase.send(:include, ActiveModelSerializers::Test::Serializer)
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,10 @@
1
+ module ActiveModelSerializers
2
+ class SerializationContext
3
+ attr_reader :request_url, :query_parameters
4
+
5
+ def initialize(request)
6
+ @request_url = request.original_url[/\A[^?]+/]
7
+ @query_parameters = request.query_parameters
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,103 @@
1
+ module ActiveModelSerializers
2
+ module Test
3
+ module Schema
4
+ # A Minitest Assertion that test the response is valid against a schema.
5
+ # @params schema_path [String] a custom schema path
6
+ # @params message [String] a custom error message
7
+ # @return [Boolean] true when the response is valid
8
+ # @return [Minitest::Assertion] when the response is invalid
9
+ # @example
10
+ # get :index
11
+ # assert_response_schema
12
+ def assert_response_schema(schema_path = nil, message = nil)
13
+ matcher = AssertResponseSchema.new(schema_path, response, message)
14
+ assert(matcher.call, matcher.message)
15
+ end
16
+
17
+ MissingSchema = Class.new(Errno::ENOENT)
18
+ InvalidSchemaError = Class.new(StandardError)
19
+
20
+ class AssertResponseSchema
21
+ attr_reader :schema_path, :response, :message
22
+
23
+ def initialize(schema_path, response, message)
24
+ require_json_schema!
25
+ @response = response
26
+ @schema_path = schema_path || schema_path_default
27
+ @message = message
28
+ @document_store = JsonSchema::DocumentStore.new
29
+ add_schema_to_document_store
30
+ end
31
+
32
+ def call
33
+ json_schema.expand_references!(store: document_store)
34
+ status, errors = json_schema.validate(response_body)
35
+ @message ||= errors.map(&:to_s).to_sentence
36
+ status
37
+ end
38
+
39
+ protected
40
+
41
+ attr_reader :document_store
42
+
43
+ def controller_path
44
+ response.request.filtered_parameters[:controller]
45
+ end
46
+
47
+ def action
48
+ response.request.filtered_parameters[:action]
49
+ end
50
+
51
+ def schema_directory
52
+ ActiveModelSerializers.config.schema_path
53
+ end
54
+
55
+ def schema_full_path
56
+ "#{schema_directory}/#{schema_path}"
57
+ end
58
+
59
+ def schema_path_default
60
+ "#{controller_path}/#{action}.json"
61
+ end
62
+
63
+ def schema_data
64
+ load_json_file(schema_full_path)
65
+ end
66
+
67
+ def response_body
68
+ load_json(response.body)
69
+ end
70
+
71
+ def json_schema
72
+ @json_schema ||= JsonSchema.parse!(schema_data)
73
+ end
74
+
75
+ def add_schema_to_document_store
76
+ Dir.glob("#{schema_directory}/**/*.json").each do |path|
77
+ schema_data = load_json_file(path)
78
+ extra_schema = JsonSchema.parse!(schema_data)
79
+ document_store.add_schema(extra_schema)
80
+ end
81
+ end
82
+
83
+ def load_json(json)
84
+ JSON.parse(json)
85
+ rescue JSON::ParserError => ex
86
+ raise InvalidSchemaError, ex.message
87
+ end
88
+
89
+ def load_json_file(path)
90
+ load_json(File.read(path))
91
+ rescue Errno::ENOENT
92
+ raise MissingSchema, "No Schema file at #{schema_full_path}"
93
+ end
94
+
95
+ def require_json_schema!
96
+ require 'json_schema'
97
+ rescue LoadError
98
+ raise LoadError, "You don't have json_schema installed in your application. Please add it to your Gemfile and run bundle install"
99
+ end
100
+ end
101
+ end
102
+ end
103
+ end
@@ -0,0 +1,125 @@
1
+ require 'set'
2
+ module ActiveModelSerializers
3
+ module Test
4
+ module Serializer
5
+ extend ActiveSupport::Concern
6
+
7
+ included do
8
+ setup :setup_serialization_subscriptions
9
+ teardown :teardown_serialization_subscriptions
10
+ end
11
+
12
+ # Asserts that the request was rendered with the appropriate serializers.
13
+ #
14
+ # # assert that the "PostSerializer" serializer was rendered
15
+ # assert_serializer "PostSerializer"
16
+ #
17
+ # # return a custom error message
18
+ # assert_serializer "PostSerializer", "PostSerializer not rendered"
19
+ #
20
+ # # assert that the instance of PostSerializer was rendered
21
+ # assert_serializer PostSerializer
22
+ #
23
+ # # assert that the "PostSerializer" serializer was rendered
24
+ # assert_serializer :post_serializer
25
+ #
26
+ # # assert that the rendered serializer starts with "Post"
27
+ # assert_serializer %r{\APost.+\Z}
28
+ #
29
+ # # assert that no serializer was rendered
30
+ # assert_serializer nil
31
+ #
32
+ def assert_serializer(expectation, message = nil)
33
+ @assert_serializer.expectation = expectation
34
+ @assert_serializer.message = message
35
+ @assert_serializer.response = response
36
+ assert(@assert_serializer.matches?, @assert_serializer.message)
37
+ end
38
+
39
+ class AssertSerializer
40
+ attr_reader :serializers, :message
41
+ attr_accessor :response, :expectation
42
+
43
+ def initialize
44
+ @serializers = Set.new
45
+ @_subscribers = []
46
+ end
47
+
48
+ def message=(message)
49
+ @message = message || "expecting <#{expectation.inspect}> but rendering with <#{serializers.to_a}>"
50
+ end
51
+
52
+ def matches?
53
+ # Force body to be read in case the template is being streamed.
54
+ response.body
55
+
56
+ case expectation
57
+ when a_serializer? then matches_class?
58
+ when Symbol then matches_symbol?
59
+ when String then matches_string?
60
+ when Regexp then matches_regexp?
61
+ when NilClass then matches_nil?
62
+ else fail ArgumentError, 'assert_serializer only accepts a String, Symbol, Regexp, ActiveModel::Serializer, or nil'
63
+ end
64
+ end
65
+
66
+ def subscribe
67
+ @_subscribers << ActiveSupport::Notifications.subscribe(event_name) do |_name, _start, _finish, _id, payload|
68
+ serializer = payload[:serializer].name
69
+ serializers << serializer
70
+ end
71
+ end
72
+
73
+ def unsubscribe
74
+ @_subscribers.each do |subscriber|
75
+ ActiveSupport::Notifications.unsubscribe(subscriber)
76
+ end
77
+ end
78
+
79
+ private
80
+
81
+ def matches_class?
82
+ serializers.include?(expectation.name)
83
+ end
84
+
85
+ def matches_symbol?
86
+ camelize_expectation = expectation.to_s.camelize
87
+ serializers.include?(camelize_expectation)
88
+ end
89
+
90
+ def matches_string?
91
+ !expectation.empty? && serializers.include?(expectation)
92
+ end
93
+
94
+ def matches_regexp?
95
+ serializers.any? do |serializer|
96
+ serializer.match(expectation)
97
+ end
98
+ end
99
+
100
+ def matches_nil?
101
+ serializers.empty?
102
+ end
103
+
104
+ def a_serializer?
105
+ ->(exp) { exp.is_a?(Class) && exp < ActiveModel::Serializer }
106
+ end
107
+
108
+ def event_name
109
+ ::ActiveModelSerializers::Logging::RENDER_EVENT
110
+ end
111
+ end
112
+
113
+ private
114
+
115
+ def setup_serialization_subscriptions
116
+ @assert_serializer = AssertSerializer.new
117
+ @assert_serializer.subscribe
118
+ end
119
+
120
+ def teardown_serialization_subscriptions
121
+ @assert_serializer.unsubscribe
122
+ end
123
+ end
124
+ end
125
+ end
@@ -0,0 +1,7 @@
1
+ module ActiveModelSerializers
2
+ module Test
3
+ extend ActiveSupport::Autoload
4
+ autoload :Serializer
5
+ autoload :Schema
6
+ end
7
+ end
@@ -1,95 +1,23 @@
1
- require "active_support"
2
- require "active_support/core_ext/string/inflections"
3
- require "active_support/notifications"
4
- require "active_model"
5
- require "active_model/array_serializer"
6
- require "active_model/serializer"
7
- require "active_model/serializer/associations"
8
- require "set"
9
-
10
- if defined?(Rails)
11
- module ActiveModel
12
- class Railtie < Rails::Railtie
13
- generators do |app|
14
- app ||= Rails.application # Rails 3.0.x does not yield `app`
15
-
16
- Rails::Generators.configure!(app.config.generators)
17
- Rails::Generators.hidden_namespaces.uniq!
18
- require_relative "generators/resource_override"
19
- end
20
-
21
- initializer "include_routes.active_model_serializer" do |app|
22
- ActiveSupport.on_load(:active_model_serializers) do
23
- include app.routes.url_helpers
24
- end
25
- end
26
-
27
- initializer "caching.active_model_serializer" do |app|
28
- ActiveModel::Serializer.perform_caching = app.config.action_controller.perform_caching
29
- ActiveModel::ArraySerializer.perform_caching = app.config.action_controller.perform_caching
30
-
31
- ActiveModel::Serializer.cache = Rails.cache
32
- ActiveModel::ArraySerializer.cache = Rails.cache
33
- end
34
- end
35
- end
36
- end
37
-
38
- module ActiveModel::SerializerSupport
39
- extend ActiveSupport::Concern
40
-
41
- module ClassMethods #:nodoc:
42
- if "".respond_to?(:safe_constantize)
43
- def active_model_serializer
44
- "#{self.name}Serializer".safe_constantize
45
- end
46
- else
47
- def active_model_serializer
48
- begin
49
- "#{self.name}Serializer".constantize
50
- rescue NameError => e
51
- raise unless e.message =~ /uninitialized constant/
52
- end
53
- end
54
- end
1
+ require 'active_model'
2
+ require 'active_support'
3
+ require 'active_support/core_ext/object/with_options'
4
+ module ActiveModelSerializers
5
+ extend ActiveSupport::Autoload
6
+ autoload :Model
7
+ autoload :Callbacks
8
+ autoload :Deserialization
9
+ autoload :Logging
10
+ autoload :Test
11
+
12
+ class << self; attr_accessor :logger; end
13
+ self.logger = ActiveSupport::TaggedLogging.new(ActiveSupport::Logger.new(STDOUT))
14
+
15
+ def self.config
16
+ ActiveModel::Serializer.config
55
17
  end
56
18
 
57
- # Returns a model serializer for this object considering its namespace.
58
- def active_model_serializer
59
- self.class.active_model_serializer
60
- end
61
-
62
- alias :read_attribute_for_serialization :send
19
+ require 'active_model/serializer/version'
20
+ require 'active_model/serializer'
21
+ require 'active_model/serializable_resource'
22
+ require 'active_model_serializers/railtie' if defined?(::Rails)
63
23
  end
64
-
65
- module ActiveModel::ArraySerializerSupport
66
- def active_model_serializer
67
- ActiveModel::ArraySerializer
68
- end
69
- end
70
-
71
- Array.send(:include, ActiveModel::ArraySerializerSupport)
72
- Set.send(:include, ActiveModel::ArraySerializerSupport)
73
-
74
- {
75
- :active_record => 'ActiveRecord::Relation',
76
- :mongoid => 'Mongoid::Criteria'
77
- }.each do |orm, rel_class|
78
- ActiveSupport.on_load(orm) do
79
- include ActiveModel::SerializerSupport
80
- rel_class.constantize.send(:include, ActiveModel::ArraySerializerSupport)
81
- end
82
- end
83
-
84
- begin
85
- require 'action_controller'
86
- require 'action_controller/serialization'
87
-
88
- ActiveSupport.on_load(:action_controller) do
89
- include ::ActionController::Serialization
90
- end
91
- rescue LoadError => ex
92
- # rails on installed, continuing
93
- end
94
-
95
- ActiveSupport.run_load_hooks(:active_model_serializers, ActiveModel::Serializer)
@@ -0,0 +1,6 @@
1
+ Description:
2
+ Generates a serializer for the given resource.
3
+
4
+ Example:
5
+ `rails generate serializer Account name created_at`
6
+
@@ -0,0 +1,10 @@
1
+ require 'rails/generators'
2
+ require 'rails/generators/rails/resource/resource_generator'
3
+
4
+ module Rails
5
+ module Generators
6
+ class ResourceGenerator
7
+ hook_for :serializer, default: true, boolean: true
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,36 @@
1
+ module Rails
2
+ module Generators
3
+ class SerializerGenerator < NamedBase
4
+ source_root File.expand_path('../templates', __FILE__)
5
+ check_class_collision :suffix => 'Serializer'
6
+
7
+ argument :attributes, :type => :array, :default => [], :banner => 'field:type field:type'
8
+
9
+ class_option :parent, :type => :string, :desc => 'The parent class for the generated serializer'
10
+
11
+ def create_serializer_file
12
+ template 'serializer.rb.erb', File.join('app/serializers', class_path, "#{file_name}_serializer.rb")
13
+ end
14
+
15
+ private
16
+
17
+ def attributes_names
18
+ [:id] + attributes.reject(&:reference?).map! { |a| a.name.to_sym }
19
+ end
20
+
21
+ def association_names
22
+ attributes.select(&:reference?).map! { |a| a.name.to_sym }
23
+ end
24
+
25
+ def parent_class_name
26
+ if options[:parent]
27
+ options[:parent]
28
+ elsif defined?(::ApplicationSerializer)
29
+ 'ApplicationSerializer'
30
+ else
31
+ 'ActiveModel::Serializer'
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,8 @@
1
+ <% module_namespacing do -%>
2
+ class <%= class_name %>Serializer < <%= parent_class_name %>
3
+ attributes <%= attributes_names.map(&:inspect).join(", ") %>
4
+ <% association_names.each do |attribute| -%>
5
+ has_one :<%= attribute %>
6
+ <% end -%>
7
+ end
8
+ <% end -%>
@@ -0,0 +1,14 @@
1
+ # To add Grape support, require 'grape/active_model_serializers' in the base of your Grape endpoints
2
+ # Then add 'include Grape::ActiveModelSerializers' to enable the formatter and helpers
3
+ require 'active_model_serializers'
4
+ require 'grape/formatters/active_model_serializers'
5
+ require 'grape/helpers/active_model_serializers'
6
+
7
+ module Grape::ActiveModelSerializers
8
+ extend ActiveSupport::Concern
9
+
10
+ included do
11
+ formatter :json, Grape::Formatters::ActiveModelSerializers
12
+ helpers Grape::Helpers::ActiveModelSerializers
13
+ end
14
+ end
@@ -0,0 +1,15 @@
1
+ # A Grape response formatter that can be used as 'formatter :json, Grape::Formatters::ActiveModelSerializers'
2
+ #
3
+ # Serializer options can be passed as a hash from your Grape endpoint using env[:active_model_serializer_options],
4
+ # or better yet user the render helper in Grape::Helpers::ActiveModelSerializers
5
+ module Grape
6
+ module Formatters
7
+ module ActiveModelSerializers
8
+ def self.call(resource, env)
9
+ serializer_options = {}
10
+ serializer_options.merge!(env[:active_model_serializer_options]) if env[:active_model_serializer_options]
11
+ ActiveModel::SerializableResource.new(resource, serializer_options).to_json
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,16 @@
1
+ # Helpers can be included in your Grape endpoint as: helpers Grape::Helpers::ActiveModelSerializers
2
+ module Grape
3
+ module Helpers
4
+ module ActiveModelSerializers
5
+ # A convenience method for passing ActiveModelSerializers serializer options
6
+ #
7
+ # Example: To include relationships in the response: render(post, include: ['comments'])
8
+ #
9
+ # Example: To include pagination meta data: render(posts, meta: { page: posts.page, total_pages: posts.total_pages })
10
+ def render(resource, active_model_serializer_options = {})
11
+ env[:active_model_serializer_options] = active_model_serializer_options
12
+ resource
13
+ end
14
+ end
15
+ end
16
+ end