From 8482abfac716e9281ddbed4782869d2bff1dee9a Mon Sep 17 00:00:00 2001 From: Lucas Hosseini Date: Mon, 31 Aug 2015 02:32:38 +0200 Subject: [PATCH 01/14] Move `id` and `json_api_type` methods from `Serializer` to `JsonApi`. --- lib/active_model/serializer.rb | 14 -------- .../serializer/adapter/json_api.rb | 32 +++++++++++++------ test/serializers/attributes_test.rb | 6 ---- 3 files changed, 22 insertions(+), 30 deletions(-) diff --git a/lib/active_model/serializer.rb b/lib/active_model/serializer.rb index a9f0e756c..e2aa0cff6 100644 --- a/lib/active_model/serializer.rb +++ b/lib/active_model/serializer.rb @@ -146,18 +146,6 @@ def json_key @root || object.class.model_name.to_s.underscore end - def id - object.id if object - end - - def json_api_type - if config.jsonapi_resource_type == :plural - object.class.model_name.plural - else - object.class.model_name.singular - end - end - def attributes(options = {}) attributes = if options[:fields] @@ -166,8 +154,6 @@ def attributes(options = {}) self.class._attributes.dup end - attributes += options[:required_fields] if options[:required_fields] - attributes.each_with_object({}) do |name, hash| unless self.class._fragmented hash[name] = send(name) diff --git a/lib/active_model/serializer/adapter/json_api.rb b/lib/active_model/serializer/adapter/json_api.rb index 1b55a8121..ff10c2b3e 100644 --- a/lib/active_model/serializer/adapter/json_api.rb +++ b/lib/active_model/serializer/adapter/json_api.rb @@ -44,19 +44,34 @@ def fragment_cache(cached_hash, non_cached_hash) private + def resource_identifier(serializer) + type = if ActiveModel::Serializer.config.jsonapi_resource_type == :plural + serializer.object.class.model_name.plural + else + serializer.object.class.model_name.singular + end + id = serializer.object.id.to_s + + { id: id, type: type } + end + def add_relationships(resource, name, serializers) resource[:relationships] ||= {} resource[:relationships][name] ||= { data: [] } - resource[:relationships][name][:data] += serializers.map { |serializer| { type: serializer.json_api_type, id: serializer.id.to_s } } + resource[:relationships][name][:data] += serializers.map { |serializer| resource_identifier(serializer) } end def add_relationship(resource, name, serializer, val=nil) resource[:relationships] ||= {} - resource[:relationships][name] = { data: val } - if serializer && serializer.object - resource[:relationships][name][:data] = { type: serializer.json_api_type, id: serializer.id.to_s } - end + resource[:relationships][name] ||= {} + resource[:relationships][name][:data] = if val + val + elsif serializer && serializer.object + resource_identifier(serializer) + else + nil + end end def add_included(resource_name, serializers, parent = nil) @@ -100,15 +115,12 @@ def attributes_for_serializer(serializer, options) def resource_object_for(serializer, options) options[:fields] = @fieldset && @fieldset.fields_for(serializer) - options[:required_fields] = [:id, :json_api_type] cache_check(serializer) do attributes = serializer.attributes(options) + attributes.delete(:id) - result = { - id: attributes.delete(:id).to_s, - type: attributes.delete(:json_api_type) - } + result = resource_identifier(serializer) result[:attributes] = attributes if attributes.any? result diff --git a/test/serializers/attributes_test.rb b/test/serializers/attributes_test.rb index 8b039df91..e0a0981fc 100644 --- a/test/serializers/attributes_test.rb +++ b/test/serializers/attributes_test.rb @@ -23,12 +23,6 @@ def test_attributes_with_fields_option @profile_serializer.attributes(fields: [:name])) end - def test_required_fields - assert_equal({name: 'Name 1', description: 'Description 1'}, - @profile_serializer.attributes(fields: [:name, :description], required_fields: [:name])) - - end - def test_attributes_inheritance_definition assert_equal([:id, :body], @serializer_klass._attributes) end From f95f7369f07a9543efd5b7bbcb3e40e309762260 Mon Sep 17 00:00:00 2001 From: Lucas Hosseini Date: Mon, 31 Aug 2015 03:24:03 +0200 Subject: [PATCH 02/14] Refactor `add_resource_relationship`. --- .../serializer/adapter/json_api.rb | 45 ++++++------------- 1 file changed, 14 insertions(+), 31 deletions(-) diff --git a/lib/active_model/serializer/adapter/json_api.rb b/lib/active_model/serializer/adapter/json_api.rb index ff10c2b3e..2447ca037 100644 --- a/lib/active_model/serializer/adapter/json_api.rb +++ b/lib/active_model/serializer/adapter/json_api.rb @@ -55,25 +55,6 @@ def resource_identifier(serializer) { id: id, type: type } end - def add_relationships(resource, name, serializers) - resource[:relationships] ||= {} - resource[:relationships][name] ||= { data: [] } - resource[:relationships][name][:data] += serializers.map { |serializer| resource_identifier(serializer) } - end - - def add_relationship(resource, name, serializer, val=nil) - resource[:relationships] ||= {} - - resource[:relationships][name] ||= {} - resource[:relationships][name][:data] = if val - val - elsif serializer && serializer.object - resource_identifier(serializer) - else - nil - end - end - def add_included(resource_name, serializers, parent = nil) unless serializers.respond_to?(:each) return unless serializers.object @@ -148,22 +129,24 @@ def check_assoc(assoc) def add_resource_relationships(attrs, serializer, options = {}) options[:add_included] = options.fetch(:add_included, true) + attrs[:relationships] ||= {} if serializer.associations.any? serializer.associations.each do |association| key = association.key serializer = association.serializer opts = association.options - - attrs[:relationships] ||= {} - - if serializer.respond_to?(:each) - add_relationships(attrs, key, serializer) - else - if opts[:virtual_value] - add_relationship(attrs, key, nil, opts[:virtual_value]) - else - add_relationship(attrs, key, serializer) - end - end + value = if serializer.respond_to?(:each) + serializer.map { |s| resource_identifier(s) } + else + if opts[:virtual_value] + opts[:virtual_value] + elsif serializer && serializer.object + resource_identifier(serializer) + else + nil + end + end + + attrs[:relationships][association.key] = { data: value } if options[:add_included] Array(serializer).each do |s| From 343f8b96bd663a32efa9678a7525b7de12aaf720 Mon Sep 17 00:00:00 2001 From: Lucas Hosseini Date: Mon, 31 Aug 2015 06:25:20 +0200 Subject: [PATCH 03/14] Fix bug preventing id overriding. --- lib/active_model/serializer/adapter/json_api.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/active_model/serializer/adapter/json_api.rb b/lib/active_model/serializer/adapter/json_api.rb index 2447ca037..4566accb8 100644 --- a/lib/active_model/serializer/adapter/json_api.rb +++ b/lib/active_model/serializer/adapter/json_api.rb @@ -50,7 +50,8 @@ def resource_identifier(serializer) else serializer.object.class.model_name.singular end - id = serializer.object.id.to_s + id = serializer.id.to_s if serializer.respond_to?('id') + id ||= serializer.object.id.to_s { id: id, type: type } end From d9c680599a366f3982b2df18eb98c3364ed70585 Mon Sep 17 00:00:00 2001 From: Lucas Hosseini Date: Tue, 1 Sep 2015 01:41:29 +0200 Subject: [PATCH 04/14] Refactor. --- .../serializer/adapter/json_api.rb | 46 +++++++++---------- 1 file changed, 21 insertions(+), 25 deletions(-) diff --git a/lib/active_model/serializer/adapter/json_api.rb b/lib/active_model/serializer/adapter/json_api.rb index 4566accb8..23ed0fa15 100644 --- a/lib/active_model/serializer/adapter/json_api.rb +++ b/lib/active_model/serializer/adapter/json_api.rb @@ -50,8 +50,7 @@ def resource_identifier(serializer) else serializer.object.class.model_name.singular end - id = serializer.id.to_s if serializer.respond_to?('id') - id ||= serializer.object.id.to_s + id = serializer.respond_to?('id') ? serializer.id.to_s : serializer.object.id.to_s { id: id, type: type } end @@ -85,25 +84,18 @@ def add_included(resource_name, serializers, parent = nil) def attributes_for_serializer(serializer, options) if serializer.respond_to?(:each) - result = [] - serializer.each do |object| - result << resource_object_for(object, options) - end + serializer.map { |s| resource_object_for(s, options) } else - result = resource_object_for(serializer, options) + resource_object_for(serializer, options) end - result end def resource_object_for(serializer, options) options[:fields] = @fieldset && @fieldset.fields_for(serializer) cache_check(serializer) do - attributes = serializer.attributes(options) - attributes.delete(:id) - result = resource_identifier(serializer) - + attributes = serializer.attributes(options).except(:id) result[:attributes] = attributes if attributes.any? result end @@ -127,25 +119,29 @@ def check_assoc(assoc) end end + def resource_relationship_value(serializer, options = {}) + if serializer.respond_to?(:each) + serializer.map { |s| resource_identifier(s) } + else + if options[:virtual_value] + options[:virtual_value] + elsif serializer.object + resurce_identifier(serializer) + else + nil + end + end + end + def add_resource_relationships(attrs, serializer, options = {}) options[:add_included] = options.fetch(:add_included, true) - attrs[:relationships] ||= {} if serializer.associations.any? + attrs[:relationships] = {} if serializer.associations.any? serializer.associations.each do |association| key = association.key serializer = association.serializer - opts = association.options - value = if serializer.respond_to?(:each) - serializer.map { |s| resource_identifier(s) } - else - if opts[:virtual_value] - opts[:virtual_value] - elsif serializer && serializer.object - resource_identifier(serializer) - else - nil - end - end + options = association.options + value = resource_relationship_value(serializer, options) attrs[:relationships][association.key] = { data: value } From c4faafdebc195372d4f36143476524288923a039 Mon Sep 17 00:00:00 2001 From: Lucas Hosseini Date: Tue, 1 Sep 2015 09:58:48 +0200 Subject: [PATCH 05/14] Refactor `resource_identifier`. --- .../serializer/adapter/json_api.rb | 40 +++++++++++-------- 1 file changed, 23 insertions(+), 17 deletions(-) diff --git a/lib/active_model/serializer/adapter/json_api.rb b/lib/active_model/serializer/adapter/json_api.rb index 23ed0fa15..fb9bfed21 100644 --- a/lib/active_model/serializer/adapter/json_api.rb +++ b/lib/active_model/serializer/adapter/json_api.rb @@ -44,13 +44,25 @@ def fragment_cache(cached_hash, non_cached_hash) private + def resource_identifier_type(serializer) + if ActiveModel::Serializer.config.jsonapi_resource_type == :singular + serializer.object.class.model_name.singular + else + serializer.object.class.model_name.plural + end + end + + def resource_identifier_id(serializer) + if serializer.respond_to?('id') + serializer.id.to_s + else + serializer.object.id.to_s + end + end + def resource_identifier(serializer) - type = if ActiveModel::Serializer.config.jsonapi_resource_type == :plural - serializer.object.class.model_name.plural - else - serializer.object.class.model_name.singular - end - id = serializer.respond_to?('id') ? serializer.id.to_s : serializer.object.id.to_s + type = resource_identifier_type(serializer) + id = resource_identifier_id(serializer) { id: id, type: type } end @@ -125,8 +137,8 @@ def resource_relationship_value(serializer, options = {}) else if options[:virtual_value] options[:virtual_value] - elsif serializer.object - resurce_identifier(serializer) + elsif serializer && serializer.object + resource_identifier(serializer) else nil end @@ -135,19 +147,13 @@ def resource_relationship_value(serializer, options = {}) def add_resource_relationships(attrs, serializer, options = {}) options[:add_included] = options.fetch(:add_included, true) - attrs[:relationships] = {} if serializer.associations.any? serializer.associations.each do |association| - key = association.key - serializer = association.serializer - options = association.options - value = resource_relationship_value(serializer, options) - + value = resource_relationship_value(association.serializer, association.options) attrs[:relationships][association.key] = { data: value } - if options[:add_included] - Array(serializer).each do |s| - add_included(key, s) + Array(association.serializer).each do |s| + add_included(association.key, s) end end end From 04012052a6e881d82083849af0fe1850d3180017 Mon Sep 17 00:00:00 2001 From: Lucas Hosseini Date: Tue, 1 Sep 2015 15:39:29 +0200 Subject: [PATCH 06/14] Fix `'id'` -> `:id`. --- lib/active_model/serializer/adapter/json_api.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/active_model/serializer/adapter/json_api.rb b/lib/active_model/serializer/adapter/json_api.rb index fb9bfed21..fb6560d83 100644 --- a/lib/active_model/serializer/adapter/json_api.rb +++ b/lib/active_model/serializer/adapter/json_api.rb @@ -53,7 +53,7 @@ def resource_identifier_type(serializer) end def resource_identifier_id(serializer) - if serializer.respond_to?('id') + if serializer.respond_to?(:id) serializer.id.to_s else serializer.object.id.to_s From f7612f2542112841c1ea1275af737ac19356c247 Mon Sep 17 00:00:00 2001 From: Lucas Hosseini Date: Tue, 1 Sep 2015 16:52:43 +0200 Subject: [PATCH 07/14] Further refactor/streamline method names. --- .../serializer/adapter/json_api.rb | 131 +++++++++--------- 1 file changed, 67 insertions(+), 64 deletions(-) diff --git a/lib/active_model/serializer/adapter/json_api.rb b/lib/active_model/serializer/adapter/json_api.rb index fb6560d83..4dc8db0b4 100644 --- a/lib/active_model/serializer/adapter/json_api.rb +++ b/lib/active_model/serializer/adapter/json_api.rb @@ -31,8 +31,10 @@ def serializable_hash(options = nil) add_links(options) else - @hash[:data] = attributes_for_serializer(serializer, options) - add_resource_relationships(@hash[:data], serializer) + @hash[:data] = attributes_for(serializer, options) + relationships = relationships_for(serializer) + @hash[:data][:relationships] = relationships if relationships.any? + add_included_relationships(serializer) end @hash end @@ -44,7 +46,7 @@ def fragment_cache(cached_hash, non_cached_hash) private - def resource_identifier_type(serializer) + def resource_identifier_type_for(serializer) if ActiveModel::Serializer.config.jsonapi_resource_type == :singular serializer.object.class.model_name.singular else @@ -52,19 +54,69 @@ def resource_identifier_type(serializer) end end - def resource_identifier_id(serializer) + def resource_identifier_id_for(serializer) if serializer.respond_to?(:id) - serializer.id.to_s + serializer.id else - serializer.object.id.to_s + serializer.object.id end end - def resource_identifier(serializer) - type = resource_identifier_type(serializer) - id = resource_identifier_id(serializer) + def resource_identifier_for(serializer) + type = resource_identifier_type_for(serializer) + id = resource_identifier_id_for(serializer) - { id: id, type: type } + { id: id.to_s, type: type } + end + + def attributes_for(serializer, options) + if serializer.respond_to?(:each) + serializer.map { |s| resource_object_for(s, options) } + else + resource_object_for(serializer, options) + end + end + + def resource_object_for(serializer, options) + options[:fields] = @fieldset && @fieldset.fields_for(serializer) + + cache_check(serializer) do + result = resource_identifier_for(serializer) + attributes = serializer.attributes(options).except(:id) + result[:attributes] = attributes if attributes.any? + result + end + end + + def relationship_value_for(serializer, options = {}) + if serializer.respond_to?(:each) + serializer.map { |s| resource_identifier_for(s) } + else + if options[:virtual_value] + options[:virtual_value] + elsif serializer && serializer.object + resource_identifier_for(serializer) + else + nil + end + end + end + + def relationships_for(serializer) + relationships = {} + serializer.associations.each do |association| + value = relationship_value_for(association.serializer, association.options) + relationships[association.key] = { data: value } + end + relationships + end + + def add_included_relationships(serializer) + serializer.associations.each do |association| + Array(association.serializer).each do |assoc_serializer| + add_included(association.key, assoc_serializer) + end + end end def add_included(resource_name, serializers, parent = nil) @@ -77,9 +129,9 @@ def add_included(resource_name, serializers, parent = nil) @hash[:included] ||= [] serializers.each do |serializer| - attrs = attributes_for_serializer(serializer, @options) - - add_resource_relationships(attrs, serializer, add_included: false) + attrs = attributes_for(serializer, @options) + relationships = relationships_for(serializer) + attrs[:relationships] = relationships if relationships.any? @hash[:included].push(attrs) unless @hash[:included].include?(attrs) end @@ -87,29 +139,8 @@ def add_included(resource_name, serializers, parent = nil) serializers.each do |serializer| serializer.associations.each do |association| - serializer = association.serializer - - add_included(association.key, serializer, resource_path) if serializer - end if include_nested_assoc? resource_path - end - end - - def attributes_for_serializer(serializer, options) - if serializer.respond_to?(:each) - serializer.map { |s| resource_object_for(s, options) } - else - resource_object_for(serializer, options) - end - end - - def resource_object_for(serializer, options) - options[:fields] = @fieldset && @fieldset.fields_for(serializer) - - cache_check(serializer) do - result = resource_identifier(serializer) - attributes = serializer.attributes(options).except(:id) - result[:attributes] = attributes if attributes.any? - result + add_included(association.key, association.serializer, resource_path) if association.serializer + end if include_nested_assoc?(resource_path) end end @@ -131,34 +162,6 @@ def check_assoc(assoc) end end - def resource_relationship_value(serializer, options = {}) - if serializer.respond_to?(:each) - serializer.map { |s| resource_identifier(s) } - else - if options[:virtual_value] - options[:virtual_value] - elsif serializer && serializer.object - resource_identifier(serializer) - else - nil - end - end - end - - def add_resource_relationships(attrs, serializer, options = {}) - options[:add_included] = options.fetch(:add_included, true) - attrs[:relationships] = {} if serializer.associations.any? - serializer.associations.each do |association| - value = resource_relationship_value(association.serializer, association.options) - attrs[:relationships][association.key] = { data: value } - if options[:add_included] - Array(association.serializer).each do |s| - add_included(association.key, s) - end - end - end - end - def add_links(options) links = @hash.fetch(:links) { {} } resources = serializer.instance_variable_get(:@resource) From 91c5cbe0b9e8351d5f7baa18c57167e7f777ae38 Mon Sep 17 00:00:00 2001 From: Lucas Hosseini Date: Tue, 1 Sep 2015 17:57:30 +0200 Subject: [PATCH 08/14] Cleanup `add_included`. --- .../serializer/adapter/json_api.rb | 39 ++++++++++--------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/lib/active_model/serializer/adapter/json_api.rb b/lib/active_model/serializer/adapter/json_api.rb index 4dc8db0b4..78d1fd5dc 100644 --- a/lib/active_model/serializer/adapter/json_api.rb +++ b/lib/active_model/serializer/adapter/json_api.rb @@ -9,6 +9,11 @@ def initialize(serializer, options = {}) super @hash = { data: [] } + @options[:include] ||= [] + if @options[:include].is_a?(String) + @options[:include] = @options[:include].split(',') + end + if fields = options.delete(:fields) @fieldset = ActiveModel::Serializer::Fieldset.new(fields, serializer.json_key) else @@ -119,47 +124,43 @@ def add_included_relationships(serializer) end end - def add_included(resource_name, serializers, parent = nil) - unless serializers.respond_to?(:each) - return unless serializers.object - serializers = Array(serializers) + def add_included(resource_name, serializer, parent = nil) + if serializer.respond_to?(:each) + serializer.each { |s| add_included(resource_name, s, parent) } + return + else + return unless serializer.object end + resource_path = [parent, resource_name].compact.join('.') + if include_assoc?(resource_path) @hash[:included] ||= [] - serializers.each do |serializer| - attrs = attributes_for(serializer, @options) - relationships = relationships_for(serializer) - attrs[:relationships] = relationships if relationships.any? + attrs = attributes_for(serializer, @options) + relationships = relationships_for(serializer) + attrs[:relationships] = relationships if relationships.any? - @hash[:included].push(attrs) unless @hash[:included].include?(attrs) - end + @hash[:included].push(attrs) unless @hash[:included].include?(attrs) end - serializers.each do |serializer| + if include_nested_assoc?(resource_path) serializer.associations.each do |association| add_included(association.key, association.serializer, resource_path) if association.serializer - end if include_nested_assoc?(resource_path) + end end end def include_assoc?(assoc) - return false unless @options[:include] check_assoc("#{assoc}$") end def include_nested_assoc?(assoc) - return false unless @options[:include] check_assoc("#{assoc}.") end def check_assoc(assoc) - include_opt = @options[:include] - include_opt = include_opt.split(',') if include_opt.is_a?(String) - include_opt.any? do |s| - s.match(/^#{assoc.gsub('.', '\.')}/) - end + @options[:include].any? { |s| s.match(/^#{assoc.gsub('.', '\.')}/) } end def add_links(options) From bae4951e058059c6bb205d21cfba433671e64be2 Mon Sep 17 00:00:00 2001 From: Lucas Hosseini Date: Tue, 1 Sep 2015 20:15:27 +0200 Subject: [PATCH 09/14] Further cleanup `included_for`. --- .../serializer/adapter/json_api.rb | 52 +++++++++---------- 1 file changed, 25 insertions(+), 27 deletions(-) diff --git a/lib/active_model/serializer/adapter/json_api.rb b/lib/active_model/serializer/adapter/json_api.rb index 78d1fd5dc..812a2b103 100644 --- a/lib/active_model/serializer/adapter/json_api.rb +++ b/lib/active_model/serializer/adapter/json_api.rb @@ -39,7 +39,8 @@ def serializable_hash(options = nil) @hash[:data] = attributes_for(serializer, options) relationships = relationships_for(serializer) @hash[:data][:relationships] = relationships if relationships.any? - add_included_relationships(serializer) + included = included_for(serializer) + @hash[:included] = included if included.any? end @hash end @@ -116,38 +117,35 @@ def relationships_for(serializer) relationships end - def add_included_relationships(serializer) - serializer.associations.each do |association| - Array(association.serializer).each do |assoc_serializer| - add_included(association.key, assoc_serializer) - end - end + def included_for(serializer) + serializer.associations.flat_map { |assoc| _included_for(assoc.key, assoc.serializer) }.uniq end - def add_included(resource_name, serializer, parent = nil) + def _included_for(resource_name, serializer, parent = nil) if serializer.respond_to?(:each) - serializer.each { |s| add_included(resource_name, s, parent) } - return + serializer.flat_map { |s| _included_for(resource_name, s, parent) }.uniq else - return unless serializer.object - end - - resource_path = [parent, resource_name].compact.join('.') - - if include_assoc?(resource_path) - @hash[:included] ||= [] - - attrs = attributes_for(serializer, @options) - relationships = relationships_for(serializer) - attrs[:relationships] = relationships if relationships.any? - - @hash[:included].push(attrs) unless @hash[:included].include?(attrs) - end + result = [] + if serializer && serializer.object + resource_path = [parent, resource_name].compact.join('.') + + if include_assoc?(resource_path) + attrs = attributes_for(serializer, @options) + relationships = relationships_for(serializer) + attrs[:relationships] = relationships if relationships.any? + result.push(attrs) + end - if include_nested_assoc?(resource_path) - serializer.associations.each do |association| - add_included(association.key, association.serializer, resource_path) if association.serializer + if include_nested_assoc?(resource_path) + serializer.associations.each do |association| + if association.serializer + result.concat(_included_for(association.key, association.serializer, resource_path)) + result.uniq! + end + end + end end + result end end From c593adbcb23c98f428e3101fcb682d0b552971bb Mon Sep 17 00:00:00 2001 From: Lucas Hosseini Date: Tue, 1 Sep 2015 20:46:18 +0200 Subject: [PATCH 10/14] Further cleanup `add_included`. --- .../serializer/adapter/json_api.rb | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/lib/active_model/serializer/adapter/json_api.rb b/lib/active_model/serializer/adapter/json_api.rb index 812a2b103..23b41b2df 100644 --- a/lib/active_model/serializer/adapter/json_api.rb +++ b/lib/active_model/serializer/adapter/json_api.rb @@ -36,7 +36,7 @@ def serializable_hash(options = nil) add_links(options) else - @hash[:data] = attributes_for(serializer, options) + @hash[:data] = resource_objects_for(serializer, options) relationships = relationships_for(serializer) @hash[:data][:relationships] = relationships if relationships.any? included = included_for(serializer) @@ -75,15 +75,7 @@ def resource_identifier_for(serializer) { id: id.to_s, type: type } end - def attributes_for(serializer, options) - if serializer.respond_to?(:each) - serializer.map { |s| resource_object_for(s, options) } - else - resource_object_for(serializer, options) - end - end - - def resource_object_for(serializer, options) + def resource_object_for(serializer, options = {}) options[:fields] = @fieldset && @fieldset.fields_for(serializer) cache_check(serializer) do @@ -94,6 +86,14 @@ def resource_object_for(serializer, options) end end + def resource_objects_for(serializer, options) + if serializer.respond_to?(:each) + serializer.map { |s| resource_object_for(s, options) } + else + resource_object_for(serializer, options) + end + end + def relationship_value_for(serializer, options = {}) if serializer.respond_to?(:each) serializer.map { |s| resource_identifier_for(s) } @@ -130,10 +130,10 @@ def _included_for(resource_name, serializer, parent = nil) resource_path = [parent, resource_name].compact.join('.') if include_assoc?(resource_path) - attrs = attributes_for(serializer, @options) + resource_object = resource_object_for(serializer, @options) relationships = relationships_for(serializer) - attrs[:relationships] = relationships if relationships.any? - result.push(attrs) + resource_object[:relationships] = relationships if relationships.any? + result.push(resource_object) end if include_nested_assoc?(resource_path) From a8a0566d29dc6ac2bd248aa2eb10f6ac1f8c69b4 Mon Sep 17 00:00:00 2001 From: Lucas Hosseini Date: Tue, 1 Sep 2015 21:16:00 +0200 Subject: [PATCH 11/14] Refactor `relationships_for`. --- lib/active_model/serializer/adapter/json_api.rb | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/lib/active_model/serializer/adapter/json_api.rb b/lib/active_model/serializer/adapter/json_api.rb index 23b41b2df..767c9c26f 100644 --- a/lib/active_model/serializer/adapter/json_api.rb +++ b/lib/active_model/serializer/adapter/json_api.rb @@ -109,12 +109,7 @@ def relationship_value_for(serializer, options = {}) end def relationships_for(serializer) - relationships = {} - serializer.associations.each do |association| - value = relationship_value_for(association.serializer, association.options) - relationships[association.key] = { data: value } - end - relationships + serializer.associations.map { |association| [ association.key, { data: relationship_value_for(association.serializer, association.options) } ] }.to_h end def included_for(serializer) From f8c553a0edeae111533050c109b0cd0565ff4348 Mon Sep 17 00:00:00 2001 From: Lucas Hosseini Date: Tue, 1 Sep 2015 21:18:27 +0200 Subject: [PATCH 12/14] Cleanup. --- lib/active_model/serializer/adapter/json_api.rb | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/active_model/serializer/adapter/json_api.rb b/lib/active_model/serializer/adapter/json_api.rb index 767c9c26f..6b87caaa9 100644 --- a/lib/active_model/serializer/adapter/json_api.rb +++ b/lib/active_model/serializer/adapter/json_api.rb @@ -36,10 +36,11 @@ def serializable_hash(options = nil) add_links(options) else - @hash[:data] = resource_objects_for(serializer, options) + resource_objects = resource_objects_for(serializer, options) relationships = relationships_for(serializer) - @hash[:data][:relationships] = relationships if relationships.any? included = included_for(serializer) + @hash[:data] = resource_objects + @hash[:data][:relationships] = relationships if relationships.any? @hash[:included] = included if included.any? end @hash @@ -109,7 +110,7 @@ def relationship_value_for(serializer, options = {}) end def relationships_for(serializer) - serializer.associations.map { |association| [ association.key, { data: relationship_value_for(association.serializer, association.options) } ] }.to_h + Hash[serializer.associations.map { |association| [ association.key, { data: relationship_value_for(association.serializer, association.options) } ] }] end def included_for(serializer) From 3793f3ff4b00b89d6731c01a3b9e93744c5bfe59 Mon Sep 17 00:00:00 2001 From: Lucas Hosseini Date: Wed, 2 Sep 2015 19:27:40 +0200 Subject: [PATCH 13/14] Rename `resource_objects_for` to `primary_data_for`. --- lib/active_model/serializer/adapter/json_api.rb | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/active_model/serializer/adapter/json_api.rb b/lib/active_model/serializer/adapter/json_api.rb index 6b87caaa9..9a8118bfe 100644 --- a/lib/active_model/serializer/adapter/json_api.rb +++ b/lib/active_model/serializer/adapter/json_api.rb @@ -36,10 +36,10 @@ def serializable_hash(options = nil) add_links(options) else - resource_objects = resource_objects_for(serializer, options) + primary_data = primary_data_for(serializer, options) relationships = relationships_for(serializer) included = included_for(serializer) - @hash[:data] = resource_objects + @hash[:data] = primary_data @hash[:data][:relationships] = relationships if relationships.any? @hash[:included] = included if included.any? end @@ -87,7 +87,7 @@ def resource_object_for(serializer, options = {}) end end - def resource_objects_for(serializer, options) + def primary_data_for(serializer, options) if serializer.respond_to?(:each) serializer.map { |s| resource_object_for(s, options) } else @@ -126,10 +126,10 @@ def _included_for(resource_name, serializer, parent = nil) resource_path = [parent, resource_name].compact.join('.') if include_assoc?(resource_path) - resource_object = resource_object_for(serializer, @options) + primary_data = primary_data_for(serializer, @options) relationships = relationships_for(serializer) - resource_object[:relationships] = relationships if relationships.any? - result.push(resource_object) + primary_data[:relationships] = relationships if relationships.any? + result.push(primary_data) end if include_nested_assoc?(resource_path) From f27f13ccc15664b1df2f683aa9fd28d89c1b1ed0 Mon Sep 17 00:00:00 2001 From: Lucas Hosseini Date: Sun, 6 Sep 2015 19:18:36 +0200 Subject: [PATCH 14/14] Fix style. --- .../serializer/adapter/json_api.rb | 46 +++++++++---------- 1 file changed, 21 insertions(+), 25 deletions(-) diff --git a/lib/active_model/serializer/adapter/json_api.rb b/lib/active_model/serializer/adapter/json_api.rb index 974e4c63a..ac3bf4a11 100644 --- a/lib/active_model/serializer/adapter/json_api.rb +++ b/lib/active_model/serializer/adapter/json_api.rb @@ -14,7 +14,8 @@ def initialize(serializer, options = {}) @options[:include] = @options[:include].split(',') end - if fields = options.delete(:fields) + fields = options.delete(:fields) + if fields @fieldset = ActiveModel::Serializer::Fieldset.new(fields, serializer.json_key) else @fieldset = options[:fieldset] @@ -48,7 +49,7 @@ def serializable_hash(options = nil) def fragment_cache(cached_hash, non_cached_hash) root = false if @options.include?(:include) - JsonApi::FragmentCache.new().fragment_cache(root, cached_hash, non_cached_hash) + JsonApi::FragmentCache.new.fragment_cache(root, cached_hash, non_cached_hash) end private @@ -103,14 +104,12 @@ def relationship_value_for(serializer, options = {}) options[:virtual_value] elsif serializer && serializer.object resource_identifier_for(serializer) - else - nil end end end def relationships_for(serializer) - Hash[serializer.associations.map { |association| [ association.key, { data: relationship_value_for(association.serializer, association.options) } ] }] + Hash[serializer.associations.map { |association| [association.key, { data: relationship_value_for(association.serializer, association.options) }] }] end def included_for(serializer) @@ -121,24 +120,23 @@ def _included_for(resource_name, serializer, parent = nil) if serializer.respond_to?(:each) serializer.flat_map { |s| _included_for(resource_name, s, parent) }.uniq else + return [] unless serializer && serializer.object result = [] - if serializer && serializer.object - resource_path = [parent, resource_name].compact.join('.') - - if include_assoc?(resource_path) - primary_data = primary_data_for(serializer, @options) - relationships = relationships_for(serializer) - primary_data[:relationships] = relationships if relationships.any? - result.push(primary_data) - end + resource_path = [parent, resource_name].compact.join('.') + + if include_assoc?(resource_path) + primary_data = primary_data_for(serializer, @options) + relationships = relationships_for(serializer) + primary_data[:relationships] = relationships if relationships.any? + result.push(primary_data) + end - if include_nested_assoc?(resource_path) - serializer.associations.each do |association| - if association.serializer - result.concat(_included_for(association.key, association.serializer, resource_path)) - result.uniq! - end - end + if include_nested_assoc?(resource_path) + non_empty_associations = serializer.associations.select(&:serializer) + + non_empty_associations.each do |association| + result.concat(_included_for(association.key, association.serializer, resource_path)) + result.uniq! end end result @@ -160,9 +158,7 @@ def check_assoc(assoc) def add_links(options) links = @hash.fetch(:links) { {} } collection = serializer.object - if is_paginated?(collection) - @hash[:links] = add_pagination_links(links, collection, options) - end + @hash[:links] = add_pagination_links(links, collection, options) if paginated?(collection) end def add_pagination_links(links, collection, options) @@ -170,7 +166,7 @@ def add_pagination_links(links, collection, options) links.update(pagination_links) end - def is_paginated?(collection) + def paginated?(collection) collection.respond_to?(:current_page) && collection.respond_to?(:total_pages) && collection.respond_to?(:size)