From a30f53de768022bc8c72dc4bcefb5c9c07fa2fb7 Mon Sep 17 00:00:00 2001 From: Jan Wendt Date: Fri, 18 Mar 2016 09:20:11 +0100 Subject: [PATCH] merge multiple nested associations --- .gitignore | 1 + .travis.yml | 13 ++--- Gemfile | 54 +++++++++++++------ appveyor.yml | 27 ++++++++++ lib/active_model/serializer.rb | 6 ++- test/fixtures/poro.rb | 38 ++++++++++++- .../serializer/associations_test.rb | 30 +++++++++++ 7 files changed, 145 insertions(+), 24 deletions(-) create mode 100644 appveyor.yml diff --git a/.gitignore b/.gitignore index 0649969e..b324b3a3 100644 --- a/.gitignore +++ b/.gitignore @@ -17,3 +17,4 @@ test/version_tmp tmp *.swp .ruby-version +vendor/bundle diff --git a/.travis.yml b/.travis.yml index c49ff981..93507aa7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,17 +11,18 @@ rvm: sudo: false -install: - - bundle install --retry=3 +install: bundle install --path=vendor/bundle --retry=3 --jobs=3 +cache: + directories: + - vendor/bundle env: - - "RAILS_VERSION=3.2.17" - - "RAILS_VERSION=4.0.3" - - "RAILS_VERSION=4.1.0" + - "RAILS_VERSION=4.0" + - "RAILS_VERSION=4.1" + - "RAILS_VERSION=4.2" - "RAILS_VERSION=master" matrix: allow_failures: - rvm: ruby-head - env: "RAILS_VERSION=master" - diff --git a/Gemfile b/Gemfile index baf8c243..cbd8ddd1 100644 --- a/Gemfile +++ b/Gemfile @@ -2,25 +2,47 @@ source 'https://rubygems.org' gemspec -platforms :ruby do - # sqlite3 1.3.9 does not work with rubinius 2.2.5: - # https://github.com/sparklemotion/sqlite3-ruby/issues/122 - gem 'sqlite3', '1.3.8' +version = ENV["RAILS_VERSION"] || "4.2" + +if version == 'master' + gem 'rack', github: 'rack/rack' + git 'https://github.com/rails/rails.git' do + gem 'railties' + gem 'activesupport' + gem 'activemodel' + gem 'actionpack' + # Rails 5 + gem 'actionview' + end + # Rails 5 + gem 'rails-controller-testing', github: 'rails/rails-controller-testing' +else + gem_version = "~> #{version}.0" + gem 'railties', gem_version + gem 'activesupport', gem_version + gem 'activemodel', gem_version + gem 'actionpack', gem_version end -platforms :jruby do - gem 'activerecord-jdbcsqlite3-adapter' +if RUBY_VERSION < '2' + gem 'mime-types', [ '>= 2.6.2', '< 3' ] end -version = ENV["RAILS_VERSION"] || "4.0.2" -rails = case version - when "master" - {:github => "rails/rails"} - else - "~> #{version}" - end -gem "rails", rails +# https://github.com/bundler/bundler/blob/89a8778c19269561926cea172acdcda241d26d23/lib/bundler/dependency.rb#L30-L54 +@windows_platforms = [:mswin, :mingw, :x64_mingw] -if version < "4" - gem "minitest", "~> 4.7.5" +# Windows does not include zoneinfo files, so bundle the tzinfo-data gem +gem 'tzinfo-data', platforms: (@windows_platforms + [:jruby]) + +group :test do + gem 'activerecord' + gem 'sqlite3', platform: (@windows_platforms + [:ruby]) + gem 'activerecord-jdbcsqlite3-adapter', platform: :jruby + + gem 'codeclimate-test-reporter', require: false + gem 'simplecov', '~> 0.10', require: false, group: :development +end + +group :development, :test do + gem 'rubocop', '~> 0.34.0', require: false end diff --git a/appveyor.yml b/appveyor.yml new file mode 100644 index 00000000..a3326f8d --- /dev/null +++ b/appveyor.yml @@ -0,0 +1,27 @@ +version: '{build}' + +skip_tags: true + +environment: + matrix: + - ruby_version: "200" + - ruby_version: "200-x64" + - ruby_version: "21" + - ruby_version: "21-x64" + +cache: + - vendor/bundle + +install: + - SET PATH=C:\Ruby%ruby_version%\bin;%PATH% + - ruby --version + - gem --version + - gem install bundler + - bundler --version + - bundle platform + - bundle install --path=vendor/bundle --retry=3 --jobs=3 + +test_script: + - bundle exec rake test + +build: off diff --git a/lib/active_model/serializer.rb b/lib/active_model/serializer.rb index 69586efd..9b3d6e6c 100644 --- a/lib/active_model/serializer.rb +++ b/lib/active_model/serializer.rb @@ -205,7 +205,11 @@ end # we must do this always because even if the current association is not # embeded in root, it might have its own associations that are embeded in root hash.merge!(association_serializer.embedded_in_root_associations) do |key, oldval, newval| - oldval.merge(newval) { |_, oldval, newval| [oldval, newval].flatten.uniq } + if oldval.respond_to?(:to_ary) + [oldval, newval].flatten.uniq + else + oldval.merge(newval) { |_, oldval, newval| [oldval, newval].flatten.uniq } + end end if association.embed_in_root? diff --git a/test/fixtures/poro.rb b/test/fixtures/poro.rb index 7a9741b4..e9d36fc0 100644 --- a/test/fixtures/poro.rb +++ b/test/fixtures/poro.rb @@ -53,6 +53,26 @@ class SpecialPost < Post end end +class Type < Model +end + +class SelfReferencingUser < Model + def type + @type ||= Type.new(name: 'N1') + end + def parent + @parent ||= SelfReferencingUserParent.new(name: 'N1') + end +end + +class SelfReferencingUserParent < Model + def type + @type ||= Type.new(name: 'N2') + end + def parent + end +end + class Comment < Model end @@ -87,6 +107,22 @@ class UserSerializer < ActiveModel::Serializer has_one :profile end +class TypeSerializer < ActiveModel::Serializer + attributes :name +end + +class SelfReferencingUserParentSerializer < ActiveModel::Serializer + attributes :name + has_one :type, serializer: TypeSerializer, embed: :ids, include: true +end + +class SelfReferencingUserSerializer < ActiveModel::Serializer + attributes :name + + has_one :type, serializer: TypeSerializer, embed: :ids, include: true + has_one :parent, serializer: SelfReferencingUserSerializer, embed: :ids, include: true +end + class UserInfoSerializer < ActiveModel::Serializer has_one :user, serializer: UserSerializer end @@ -176,7 +212,7 @@ end class NameKeyPostSerializer < ActiveModel::Serializer attributes :title, :body - + has_many :comments end diff --git a/test/unit/active_model/serializer/associations_test.rb b/test/unit/active_model/serializer/associations_test.rb index 4a1e0b22..7f014941 100644 --- a/test/unit/active_model/serializer/associations_test.rb +++ b/test/unit/active_model/serializer/associations_test.rb @@ -14,6 +14,36 @@ module ActiveModel assert_equal([:comments], another_inherited_serializer_klass._associations.keys) end + def test_multiple_nested_associations + parent = SelfReferencingUserParent.new(name: "The Parent") + child = SelfReferencingUser.new(name: "The child", parent: parent) + self_referencing_user_serializer = SelfReferencingUserSerializer.new(child) + result = self_referencing_user_serializer.as_json + expected_result = { + "self_referencing_user"=>{ + :name=>"The child", + "type_id"=>child.type.object_id, + "parent_id"=>child.parent.object_id + + }, + "types"=>[ + { + :name=>"N1", + }, + { + :name=>"N2", + } + ], + "parents"=>[ + { + :name=>"N1", + "type_id"=>child.parent.type.object_id, + "parent_id"=>nil + } + ] + } + assert_equal(expected_result, result) + end end end end