active_model_serializers 0.8.3 → 0.9.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (89) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +122 -5
  3. data/CONTRIBUTING.md +20 -0
  4. data/DESIGN.textile +4 -4
  5. data/{MIT-LICENSE.txt → MIT-LICENSE} +0 -0
  6. data/README.md +396 -95
  7. data/lib/action_controller/serialization.rb +50 -12
  8. data/lib/action_controller/serialization_test_case.rb +79 -0
  9. data/lib/active_model/array_serializer.rb +47 -78
  10. data/lib/active_model/default_serializer.rb +32 -0
  11. data/lib/active_model/serializable/utils.rb +16 -0
  12. data/lib/active_model/serializable.rb +62 -0
  13. data/lib/active_model/serializer/association/has_many.rb +39 -0
  14. data/lib/active_model/serializer/association/has_one.rb +25 -0
  15. data/lib/active_model/serializer/association.rb +58 -0
  16. data/lib/active_model/serializer/config.rb +31 -0
  17. data/lib/active_model/serializer/generators/resource_override.rb +13 -0
  18. data/lib/{generators → active_model/serializer/generators}/serializer/USAGE +0 -0
  19. data/lib/active_model/serializer/generators/serializer/scaffold_controller_generator.rb +14 -0
  20. data/lib/active_model/serializer/generators/serializer/serializer_generator.rb +37 -0
  21. data/lib/active_model/serializer/generators/serializer/templates/controller.rb +93 -0
  22. data/lib/active_model/serializer/generators/serializer/templates/serializer.rb +8 -0
  23. data/lib/active_model/serializer/railtie.rb +18 -0
  24. data/lib/active_model/{serializers → serializer}/version.rb +1 -1
  25. data/lib/active_model/serializer.rb +214 -423
  26. data/lib/active_model/serializer_support.rb +5 -0
  27. data/lib/active_model_serializers/mime_types.rb +14 -0
  28. data/lib/active_model_serializers.rb +12 -87
  29. data/test/fixtures/active_record.rb +96 -0
  30. data/test/fixtures/poro.rb +187 -0
  31. data/test/fixtures/template.html.erb +1 -0
  32. data/test/integration/action_controller/namespaced_serialization_test.rb +105 -0
  33. data/test/integration/action_controller/serialization_test.rb +287 -0
  34. data/test/integration/action_controller/serialization_test_case_test.rb +71 -0
  35. data/test/integration/active_record/active_record_test.rb +94 -0
  36. data/test/integration/generators/resource_generator_test.rb +26 -0
  37. data/test/integration/generators/scaffold_controller_generator_test.rb +64 -0
  38. data/test/integration/generators/serializer_generator_test.rb +41 -0
  39. data/test/test_app.rb +14 -0
  40. data/test/test_helper.rb +10 -18
  41. data/test/unit/active_model/array_serializer/except_test.rb +18 -0
  42. data/test/unit/active_model/array_serializer/key_format_test.rb +18 -0
  43. data/test/unit/active_model/array_serializer/meta_test.rb +53 -0
  44. data/test/unit/active_model/array_serializer/only_test.rb +18 -0
  45. data/test/unit/active_model/array_serializer/options_test.rb +16 -0
  46. data/test/unit/active_model/array_serializer/root_test.rb +102 -0
  47. data/test/unit/active_model/array_serializer/scope_test.rb +24 -0
  48. data/test/unit/active_model/array_serializer/serialization_test.rb +216 -0
  49. data/test/unit/active_model/default_serializer_test.rb +13 -0
  50. data/test/unit/active_model/serializer/associations/build_serializer_test.rb +36 -0
  51. data/test/unit/active_model/serializer/associations_test.rb +19 -0
  52. data/test/unit/active_model/serializer/attributes_test.rb +57 -0
  53. data/test/unit/active_model/serializer/config_test.rb +91 -0
  54. data/test/unit/active_model/serializer/filter_test.rb +69 -0
  55. data/test/unit/active_model/serializer/has_many_polymorphic_test.rb +189 -0
  56. data/test/unit/active_model/serializer/has_many_test.rb +265 -0
  57. data/test/unit/active_model/serializer/has_one_and_has_many_test.rb +27 -0
  58. data/test/unit/active_model/serializer/has_one_polymorphic_test.rb +196 -0
  59. data/test/unit/active_model/serializer/has_one_test.rb +253 -0
  60. data/test/unit/active_model/serializer/key_format_test.rb +25 -0
  61. data/test/unit/active_model/serializer/meta_test.rb +39 -0
  62. data/test/unit/active_model/serializer/options_test.rb +42 -0
  63. data/test/unit/active_model/serializer/root_test.rb +117 -0
  64. data/test/unit/active_model/serializer/scope_test.rb +49 -0
  65. data/test/unit/active_model/serializer/url_helpers_test.rb +35 -0
  66. metadata +107 -64
  67. data/.gitignore +0 -18
  68. data/.travis.yml +0 -28
  69. data/Gemfile +0 -4
  70. data/Gemfile.edge +0 -9
  71. data/Rakefile +0 -18
  72. data/active_model_serializers.gemspec +0 -24
  73. data/bench/perf.rb +0 -43
  74. data/cruft.md +0 -19
  75. data/lib/active_model/serializer/associations.rb +0 -233
  76. data/lib/active_record/serializer_override.rb +0 -16
  77. data/lib/generators/resource_override.rb +0 -13
  78. data/lib/generators/serializer/serializer_generator.rb +0 -42
  79. data/lib/generators/serializer/templates/serializer.rb +0 -19
  80. data/test/array_serializer_test.rb +0 -75
  81. data/test/association_test.rb +0 -592
  82. data/test/caching_test.rb +0 -96
  83. data/test/generators_test.rb +0 -85
  84. data/test/no_serialization_scope_test.rb +0 -34
  85. data/test/serialization_scope_name_test.rb +0 -67
  86. data/test/serialization_test.rb +0 -392
  87. data/test/serializer_support_test.rb +0 -51
  88. data/test/serializer_test.rb +0 -1465
  89. data/test/test_fakes.rb +0 -217
@@ -1,3 +1,5 @@
1
+ require 'active_support/core_ext/class/attribute'
2
+
1
3
  module ActionController
2
4
  # Action Controller Serialization
3
5
  #
@@ -27,34 +29,70 @@ module ActionController
27
29
 
28
30
  include ActionController::Renderers
29
31
 
32
+ class << self
33
+ attr_accessor :enabled
34
+ end
35
+ self.enabled = true
36
+
30
37
  included do
31
38
  class_attribute :_serialization_scope
32
39
  self._serialization_scope = :current_user
33
40
  end
34
41
 
35
- def serialization_scope
36
- send(_serialization_scope) if _serialization_scope &&
37
- respond_to?(_serialization_scope, true)
38
- end
39
-
40
- def default_serializer_options
42
+ module ClassMethods
43
+ def serialization_scope(scope)
44
+ self._serialization_scope = scope
45
+ end
41
46
  end
42
47
 
43
48
  [:_render_option_json, :_render_with_renderer_json].each do |renderer_method|
44
49
  define_method renderer_method do |resource, options|
45
- json = ActiveModel::Serializer.build_json(self, resource, options)
50
+ serializer = build_json_serializer(resource, options)
46
51
 
47
- if json
48
- super(json, options)
52
+ if serializer
53
+ super(serializer, options)
49
54
  else
50
55
  super(resource, options)
51
56
  end
52
57
  end
53
58
  end
54
59
 
55
- module ClassMethods
56
- def serialization_scope(scope)
57
- self._serialization_scope = scope
60
+ private
61
+
62
+ def namespace_for_serializer
63
+ @namespace_for_serializer ||= self.class.parent unless self.class.parent == Object
64
+ end
65
+
66
+ def default_serializer(resource)
67
+ options = {}.tap do |o|
68
+ o[:namespace] = namespace_for_serializer if namespace_for_serializer
69
+ end
70
+
71
+ ActiveModel::Serializer.serializer_for(resource, options)
72
+ end
73
+
74
+ def default_serializer_options
75
+ {}
76
+ end
77
+
78
+ def serialization_scope
79
+ _serialization_scope = self.class._serialization_scope
80
+ send(_serialization_scope) if _serialization_scope && respond_to?(_serialization_scope, true)
81
+ end
82
+
83
+ def build_json_serializer(resource, options = {})
84
+ options = default_serializer_options.merge(options)
85
+ @namespace_for_serializer = options.fetch(:namespace, nil)
86
+
87
+ if serializer = options.fetch(:serializer, default_serializer(resource))
88
+ options[:scope] = serialization_scope unless options.has_key?(:scope)
89
+
90
+ if resource.respond_to?(:to_ary)
91
+ options[:resource_name] = controller_name
92
+ options[:namespace] = namespace_for_serializer if namespace_for_serializer
93
+ end
94
+
95
+ serializer.new(resource, options)
58
96
  end
59
97
  end
60
98
  end
@@ -0,0 +1,79 @@
1
+ module ActionController
2
+ module SerializationAssertions
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ setup :setup_serialization_subscriptions
7
+ teardown :teardown_serialization_subscriptions
8
+ end
9
+
10
+ def setup_serialization_subscriptions
11
+ @serializers = Hash.new(0)
12
+
13
+ ActiveSupport::Notifications.subscribe("!serialize.active_model_serializers") do |name, start, finish, id, payload|
14
+ serializer = payload[:serializer]
15
+ @serializers[serializer] += 1
16
+ end
17
+ end
18
+
19
+ def teardown_serialization_subscriptions
20
+ ActiveSupport::Notifications.unsubscribe("!serialize.active_model_serializers")
21
+ end
22
+
23
+ def process(*args)
24
+ @serializers = Hash.new(0)
25
+ super
26
+ end
27
+
28
+ # Asserts that the request was rendered with the appropriate serializers.
29
+ #
30
+ # # assert that the "PostSerializer" serializer was rendered
31
+ # assert_serializer "PostSerializer"
32
+ #
33
+ # # assert that the instance of PostSerializer was rendered
34
+ # assert_serializer PostSerializer
35
+ #
36
+ # # assert that the "PostSerializer" serializer was rendered
37
+ # assert_serializer :post_serializer
38
+ #
39
+ # # assert that the rendered serializer starts with "Post"
40
+ # assert_serializer %r{\APost.+\Z}
41
+ #
42
+ # # assert that no serializer was rendered
43
+ # assert_serializer nil
44
+ #
45
+ #
46
+ def assert_serializer(options = {}, message = nil)
47
+ # Force body to be read in case the template is being streamed.
48
+ response.body
49
+
50
+ rendered = @serializers
51
+ msg = message || "expecting <#{options.inspect}> but rendering with <#{rendered.keys}>"
52
+
53
+ matches_serializer = case options
54
+ when lambda { |options| options.kind_of?(Class) && options < ActiveModel::Serializer }
55
+ rendered.any? do |serializer, count|
56
+ options.name == serializer
57
+ end
58
+ when Symbol
59
+ options = options.to_s.camelize
60
+ rendered.any? do |serializer, count|
61
+ serializer == options
62
+ end
63
+ when String
64
+ !options.empty? && rendered.any? do |serializer, count|
65
+ serializer == options
66
+ end
67
+ when Regexp
68
+ rendered.any? do |serializer, count|
69
+ serializer.match(options)
70
+ end
71
+ when NilClass
72
+ rendered.blank?
73
+ else
74
+ raise ArgumentError, "assert_serializer only accepts a String, Symbol, Regexp, ActiveModel::Serializer, or nil"
75
+ end
76
+ assert matches_serializer, msg
77
+ end
78
+ end
79
+ end
@@ -1,104 +1,73 @@
1
- require "active_support/core_ext/class/attribute"
2
- require 'active_support/dependencies'
3
- require 'active_support/descendants_tracker'
1
+ require 'active_model/default_serializer'
2
+ require 'active_model/serializable'
4
3
 
5
4
  module ActiveModel
6
- # Active Model Array Serializer
7
- #
8
- # Serializes an Array, checking if each element implements
9
- # the +active_model_serializer+ method.
10
- #
11
- # To disable serialization of root elements:
12
- #
13
- # ActiveModel::ArraySerializer.root = false
14
- #
15
5
  class ArraySerializer
16
- extend ActiveSupport::DescendantsTracker
17
-
18
- attr_reader :object, :options
19
-
20
- class_attribute :root
21
-
22
- class_attribute :cache
23
- class_attribute :perform_caching
6
+ include Serializable
24
7
 
25
8
  class << self
26
- # set perform caching like root
27
- def cached(value = true)
28
- self.perform_caching = value
29
- end
9
+ attr_accessor :_root
10
+ alias root _root=
11
+ alias root= _root=
30
12
  end
31
13
 
32
14
  def initialize(object, options={})
33
- @object, @options = object, options
15
+ @object = object
16
+ @scope = options[:scope]
17
+ @root = options.fetch(:root, self.class._root)
18
+ @polymorphic = options.fetch(:polymorphic, false)
19
+ @meta_key = options[:meta_key] || :meta
20
+ @meta = options[@meta_key]
21
+ @each_serializer = options[:each_serializer]
22
+ @resource_name = options[:resource_name]
23
+ @only = options[:only] ? Array(options[:only]) : nil
24
+ @except = options[:except] ? Array(options[:except]) : nil
25
+ @context = options[:context]
26
+ @namespace = options[:namespace]
27
+ @key_format = options[:key_format] || options[:each_serializer].try(:key_format)
34
28
  end
29
+ attr_accessor :object, :scope, :root, :meta_key, :meta, :key_format, :context
35
30
 
36
- def meta_key
37
- @options[:meta_key].try(:to_sym) || :meta
38
- end
31
+ def json_key
32
+ key = root.nil? ? @resource_name : root
39
33
 
40
- def include_meta(hash)
41
- hash[meta_key] = @options[:meta] if @options.has_key?(:meta)
34
+ key_format == :lower_camel && key.present? ? key.camelize(:lower) : key
42
35
  end
43
36
 
44
- def as_json(*args)
45
- @options[:hash] = hash = {}
46
- @options[:unique_values] = {}
47
-
48
- if root = @options[:root]
49
- hash.merge!(root => serializable_array)
50
- include_meta hash
51
- hash
52
- else
53
- serializable_array
54
- end
37
+ def serializer_for(item)
38
+ serializer_class = @each_serializer || Serializer.serializer_for(item, namespace: @namespace) || DefaultSerializer
39
+ serializer_class.new(item, scope: scope, key_format: key_format, context: @context, only: @only, except: @except, polymorphic: @polymorphic, namespace: @namespace)
55
40
  end
56
41
 
57
- def to_json(*args)
58
- if perform_caching?
59
- cache.fetch expand_cache_key([self.class.to_s.underscore, cache_key, 'to-json']) do
60
- super
61
- end
62
- else
63
- super
42
+ def serializable_object(options={})
43
+ @object.map do |item|
44
+ serializer_for(item).serializable_object_with_notification(options)
64
45
  end
65
46
  end
66
-
67
- def serializable_array
68
- if perform_caching?
69
- cache.fetch expand_cache_key([self.class.to_s.underscore, cache_key, 'serializable-array']) do
70
- _serializable_array
47
+ alias_method :serializable_array, :serializable_object
48
+
49
+ def embedded_in_root_associations
50
+ @object.each_with_object({}) do |item, hash|
51
+ serializer_for(item).embedded_in_root_associations.each_pair do |type, objects|
52
+ next if !objects || objects.flatten.empty?
53
+
54
+ if hash.has_key?(type)
55
+ case hash[type] when Hash
56
+ hash[type].deep_merge!(objects){ |key, old, new| (Array(old) + Array(new)).uniq }
57
+ else
58
+ hash[type].concat(objects).uniq!
59
+ end
60
+ else
61
+ hash[type] = objects
62
+ end
71
63
  end
72
- else
73
- _serializable_array
74
64
  end
75
65
  end
76
66
 
77
67
  private
78
- def _serializable_array
79
- @object.map do |item|
80
- if @options.has_key? :each_serializer
81
- serializer = @options[:each_serializer]
82
- elsif item.respond_to?(:active_model_serializer)
83
- serializer = item.active_model_serializer
84
- end
85
-
86
- serializable = serializer ? serializer.new(item, @options) : DefaultSerializer.new(item, @options.merge(:root => false))
87
-
88
- if serializable.respond_to?(:serializable_hash)
89
- serializable.serializable_hash
90
- else
91
- serializable.as_json
92
- end
93
- end
94
- end
95
-
96
- def expand_cache_key(*args)
97
- ActiveSupport::Cache.expand_cache_key(args)
98
- end
99
68
 
100
- def perform_caching?
101
- perform_caching && cache && respond_to?(:cache_key)
69
+ def instrumentation_keys
70
+ [:object, :scope, :root, :meta_key, :meta, :each_serializer, :resource_name, :key_format, :context]
102
71
  end
103
72
  end
104
73
  end
@@ -0,0 +1,32 @@
1
+ require 'active_model/serializable'
2
+
3
+ module ActiveModel
4
+ # DefaultSerializer
5
+ #
6
+ # Provides a constant interface for all items
7
+ class DefaultSerializer
8
+ include ActiveModel::Serializable
9
+
10
+ attr_reader :object
11
+
12
+ def initialize(object, options={})
13
+ @object = object
14
+ @wrap_in_array = options[:_wrap_in_array]
15
+ end
16
+
17
+ def as_json(options={})
18
+ instrument('!serialize') do
19
+ return [] if @object.nil? && @wrap_in_array
20
+ hash = @object.as_json
21
+ @wrap_in_array ? [hash] : hash
22
+ end
23
+ end
24
+ alias serializable_hash as_json
25
+ alias serializable_object as_json
26
+
27
+ private
28
+ def instrumentation_keys
29
+ [:object, :wrap_in_array]
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,16 @@
1
+ module ActiveModel
2
+ module Serializable
3
+ module Utils
4
+ extend self
5
+
6
+ def _const_get(const)
7
+ begin
8
+ method = RUBY_VERSION >= '2.0' ? :const_get : :qualified_const_get
9
+ Object.send method, const
10
+ rescue NameError
11
+ const.safe_constantize
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,62 @@
1
+ require 'active_model/serializable/utils'
2
+
3
+ module ActiveModel
4
+ module Serializable
5
+ def self.included(base)
6
+ base.extend Utils
7
+ end
8
+
9
+ def as_json(options={})
10
+ instrument('!serialize') do
11
+ if root = options.fetch(:root, json_key)
12
+ hash = { root => serializable_object(options) }
13
+ hash.merge!(serializable_data)
14
+ hash
15
+ else
16
+ serializable_object(options)
17
+ end
18
+ end
19
+ end
20
+
21
+ def serializable_object_with_notification(options={})
22
+ instrument('!serialize') do
23
+ serializable_object(options)
24
+ end
25
+ end
26
+
27
+ def serializable_data
28
+ embedded_in_root_associations.tap do |hash|
29
+ if respond_to?(:meta) && meta
30
+ hash[meta_key] = meta
31
+ end
32
+ end
33
+ end
34
+
35
+ def namespace
36
+ get_namespace && Utils._const_get(get_namespace)
37
+ end
38
+
39
+ def embedded_in_root_associations
40
+ {}
41
+ end
42
+
43
+ private
44
+
45
+ def get_namespace
46
+ modules = self.class.name.split('::')
47
+ modules[0..-2].join('::') if modules.size > 1
48
+ end
49
+
50
+ def instrument(action, &block)
51
+ payload = instrumentation_keys.inject({ serializer: self.class.name }) do |payload, key|
52
+ payload[:payload] = self.instance_variable_get(:"@#{key}")
53
+ payload
54
+ end
55
+ ActiveSupport::Notifications.instrument("#{action}.active_model_serializers", payload, &block)
56
+ end
57
+
58
+ def instrumentation_keys
59
+ [:object, :scope, :root, :meta_key, :meta, :wrap_in_array, :only, :except, :key_format]
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,39 @@
1
+ module ActiveModel
2
+ class Serializer
3
+ class Association
4
+ class HasMany < Association
5
+ def initialize(name, *args)
6
+ super
7
+ @root_key = @embedded_key.to_s
8
+ @key ||= case CONFIG.default_key_type
9
+ when :name then name.to_s.pluralize
10
+ else "#{name.to_s.singularize}_ids"
11
+ end
12
+ end
13
+
14
+ def serializer_class(object, _)
15
+ if use_array_serializer?
16
+ ArraySerializer
17
+ else
18
+ serializer_from_options
19
+ end
20
+ end
21
+
22
+ def options
23
+ if use_array_serializer?
24
+ { each_serializer: serializer_from_options }.merge! super
25
+ else
26
+ super
27
+ end
28
+ end
29
+
30
+ private
31
+
32
+ def use_array_serializer?
33
+ !serializer_from_options ||
34
+ serializer_from_options && !(serializer_from_options <= ArraySerializer)
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,25 @@
1
+ module ActiveModel
2
+ class Serializer
3
+ class Association
4
+ class HasOne < Association
5
+ def initialize(name, *args)
6
+ super
7
+ @root_key = @embedded_key.to_s.pluralize
8
+ @key ||= case CONFIG.default_key_type
9
+ when :name then name.to_s.singularize
10
+ else "#{name}_id"
11
+ end
12
+ end
13
+
14
+ def serializer_class(object, options = {})
15
+ (serializer_from_options unless object.nil?) || serializer_from_object(object, options) || default_serializer
16
+ end
17
+
18
+ def build_serializer(object, options = {})
19
+ options[:_wrap_in_array] = embed_in_root?
20
+ super
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,58 @@
1
+ require 'active_model/default_serializer'
2
+ require 'active_model/serializer/association/has_one'
3
+ require 'active_model/serializer/association/has_many'
4
+
5
+ module ActiveModel
6
+ class Serializer
7
+ class Association
8
+ def initialize(name, options={})
9
+ if options.has_key?(:include)
10
+ ActiveSupport::Deprecation.warn <<-WARN
11
+ ** Notice: include was renamed to embed_in_root. **
12
+ WARN
13
+ end
14
+
15
+ @name = name.to_s
16
+ @options = options
17
+ self.embed = options.fetch(:embed) { CONFIG.embed }
18
+ @polymorphic = options.fetch(:polymorphic, false)
19
+ @embed_in_root = options.fetch(:embed_in_root) { options.fetch(:include) { CONFIG.embed_in_root } }
20
+ @key_format = options.fetch(:key_format) { CONFIG.key_format }
21
+ @embed_key = options[:embed_key] || :id
22
+ @key = options[:key]
23
+ @embedded_key = options[:root] || name
24
+ @embed_in_root_key = options.fetch(:embed_in_root_key) { CONFIG.embed_in_root_key }
25
+ @embed_namespace = options.fetch(:embed_namespace) { CONFIG.embed_namespace }
26
+
27
+ serializer = @options[:serializer]
28
+ @serializer_from_options = serializer.is_a?(String) ? serializer.constantize : serializer
29
+ end
30
+
31
+ attr_reader :name, :embed_ids, :embed_objects, :polymorphic
32
+ attr_accessor :embed_in_root, :embed_key, :key, :embedded_key, :root_key, :serializer_from_options, :options, :key_format, :embed_in_root_key, :embed_namespace
33
+ alias embed_ids? embed_ids
34
+ alias embed_objects? embed_objects
35
+ alias embed_in_root? embed_in_root
36
+ alias embed_in_root_key? embed_in_root_key
37
+ alias embed_namespace? embed_namespace
38
+ alias polymorphic? polymorphic
39
+
40
+ def embed=(embed)
41
+ @embed_ids = embed == :id || embed == :ids
42
+ @embed_objects = embed == :object || embed == :objects
43
+ end
44
+
45
+ def serializer_from_object(object, options = {})
46
+ Serializer.serializer_for(object, options)
47
+ end
48
+
49
+ def default_serializer
50
+ DefaultSerializer
51
+ end
52
+
53
+ def build_serializer(object, options = {})
54
+ serializer_class(object, options).new(object, options.merge(self.options))
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,31 @@
1
+ module ActiveModel
2
+ class Serializer
3
+ class Config
4
+ def initialize(data = {})
5
+ @data = data
6
+ end
7
+
8
+ def each(&block)
9
+ @data.each(&block)
10
+ end
11
+
12
+ def clear
13
+ @data.clear
14
+ end
15
+
16
+ def method_missing(name, *args)
17
+ name = name.to_s
18
+ return @data[name] if @data.include?(name)
19
+ match = name.match(/\A(.*?)([?=]?)\Z/)
20
+ case match[2]
21
+ when "="
22
+ @data[match[1]] = args.first
23
+ when "?"
24
+ !!@data[match[1]]
25
+ end
26
+ end
27
+ end
28
+
29
+ CONFIG = Config.new('embed' => :objects) # :nodoc:
30
+ end
31
+ end
@@ -0,0 +1,13 @@
1
+ require 'rails/generators'
2
+ require 'rails/generators/rails/resource/resource_generator'
3
+
4
+ module Rails
5
+ module Generators
6
+ class ResourceGenerator
7
+ def add_serializer
8
+ invoke 'serializer'
9
+ end
10
+ end
11
+ end
12
+ end
13
+
@@ -0,0 +1,14 @@
1
+ require 'rails/generators'
2
+ require 'rails/generators/rails/scaffold_controller/scaffold_controller_generator'
3
+
4
+ module Rails
5
+ module Generators
6
+ class ScaffoldControllerGenerator
7
+ if Rails::VERSION::MAJOR >= 4
8
+ source_root File.expand_path('../templates', __FILE__)
9
+
10
+ hook_for :serializer, default: true
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,37 @@
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', File.join('app/serializers', class_path, "#{file_name}_serializer.rb")
13
+ end
14
+
15
+ private
16
+
17
+ def attributes_names
18
+ [:id] + attributes.select { |attr| !attr.reference? }.map { |a| a.name.to_sym }
19
+ end
20
+
21
+ def association_names
22
+ attributes.select { |attr| attr.reference? }.map { |a| a.name.to_sym }
23
+ end
24
+
25
+ def parent_class_name
26
+ if options[:parent]
27
+ options[:parent]
28
+ elsif (ns = Rails::Generators.namespace) && ns.const_defined?(:ApplicationSerializer) ||
29
+ (Object.const_get(:ApplicationSerializer) rescue nil)
30
+ 'ApplicationSerializer'
31
+ else
32
+ 'ActiveModel::Serializer'
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end