From 4e9e889b65c69f140d6db70c7aacf39f2a74cb14 Mon Sep 17 00:00:00 2001 From: Daniel Dawson Date: Mon, 28 Mar 2016 14:39:25 +0200 Subject: [PATCH] Singularize and capitalize polymorphic types for presence validation Singularizing polymorphic association types allows you to use plural or singular type values in your requests as allowed by JSON API. Because ActiveRecord calls #constantize on the polymorphic association type when you use the hash to create a new model if you validate the presence of the related model, you must capitalize the type to avoid a NameError. --- CHANGELOG.md | 4 +++ docs/general/deserialization.md | 2 +- .../adapter/json_api/deserialization.rb | 4 +-- test/active_record_test.rb | 33 +++++++++++++++++++ test/adapter/json_api/parse_test.rb | 2 +- test/fixtures/active_record.rb | 6 ++-- test/fixtures/poro.rb | 6 ++++ 7 files changed, 51 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 304707bbe..ba20ed32f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,6 +26,10 @@ Features: - [#1340](https://github.com/rails-api/active_model_serializers/pull/1340) Add support for resource-level meta. (@beauby) Fixes: +- [#1615](https://github.com/rails-api/active_model_serializers/pull/1615) Allow plural polymorphic relationship types when validating + presence. (@dpdawson) +- [#1615](https://github.com/rails-api/active_model_serializers/pull/1615) Capitalize polymorphic association types to prevent error + when ActiveRecord constantizes them when validating presence. (@dpdawson) - [#1478](https://github.com/rails-api/active_model_serializers/pull/1478) Cache store will now be correctly set when serializers are loaded *before* Rails initializes. (@bf4) - [#1570](https://github.com/rails-api/active_model_serializers/pull/1570) Fixed pagination issue with last page size. (@bmorrall) diff --git a/docs/general/deserialization.md b/docs/general/deserialization.md index 56dda833c..543d46c88 100644 --- a/docs/general/deserialization.md +++ b/docs/general/deserialization.md @@ -91,7 +91,7 @@ ActiveModelSerializers::Deserialization # title: 'Title 1', # published_at: '2015-12-20', # author_id: '2', -# author_type: 'user' +# author_type: 'User' # } ``` diff --git a/lib/active_model_serializers/adapter/json_api/deserialization.rb b/lib/active_model_serializers/adapter/json_api/deserialization.rb index f52443552..ec2982f81 100644 --- a/lib/active_model_serializers/adapter/json_api/deserialization.rb +++ b/lib/active_model_serializers/adapter/json_api/deserialization.rb @@ -69,7 +69,7 @@ module Deserialization # # title: 'Title 1', # # published_at: '2015-12-20', # # author_id: '2', - # # author_type: 'people' + # # author_type: 'People' # # } # def parse!(document, options = {}) @@ -188,7 +188,7 @@ def parse_relationship(assoc_name, assoc_data, options) end polymorphic = (options[:polymorphic] || []).include?(assoc_name.to_sym) - hash["#{prefix_key}_type".to_sym] = assoc_data['type'] if polymorphic + hash["#{prefix_key}_type".to_sym] = assoc_data['type'].singularize.capitalize if polymorphic hash end diff --git a/test/active_record_test.rb b/test/active_record_test.rb index 5bb941a46..72a644674 100644 --- a/test/active_record_test.rb +++ b/test/active_record_test.rb @@ -5,5 +5,38 @@ class ActiveRecordTest < ActiveSupport::TestCase def setup @resource = ARModels::Post.new + @image = Image.create + end + + def test_active_model_record_with_validated_polymorphic_relationship_creation + picture = Picture.create!(picture_params) + + assert_equal(@image, picture.imageable) + end + + private + + def picture_params + params = ActionController::Parameters.new({ + data: { + attributes: { + title: 'Picture Title' + }, + relationships: { + imageable: { + data: { + type: 'images', + id: @image.id + } + }, + }, + type: 'pictures' + } + }) + + ActiveModelSerializers::Deserialization.jsonapi_parse!( + params.to_unsafe_h, + polymorphic: [:imageable] + ) end end diff --git a/test/adapter/json_api/parse_test.rb b/test/adapter/json_api/parse_test.rb index bee79c8c1..777abf3e1 100644 --- a/test/adapter/json_api/parse_test.rb +++ b/test/adapter/json_api/parse_test.rb @@ -125,7 +125,7 @@ def test_polymorphic src: 'http://example.com/images/productivity.png', author_id: nil, photographer_id: '9', - photographer_type: 'people', + photographer_type: 'Person', comment_ids: %w(1 2) } assert_equal(expected, parsed_hash) diff --git a/test/fixtures/active_record.rb b/test/fixtures/active_record.rb index 3f0b2dc09..9407dde2f 100644 --- a/test/fixtures/active_record.rb +++ b/test/fixtures/active_record.rb @@ -26,8 +26,10 @@ end create_table :pictures, force: true do |t| t.string :title - t.string :imageable_type - t.string :imageable_id + t.references :imageable, polymorphic: true + t.timestamp null: false + end + create_table :images, force: true do |t| t.timestamp null: false end end diff --git a/test/fixtures/poro.rb b/test/fixtures/poro.rb index c7fb831c8..91a3ee293 100644 --- a/test/fixtures/poro.rb +++ b/test/fixtures/poro.rb @@ -78,6 +78,12 @@ class Employee < ActiveRecord::Base class Picture < ActiveRecord::Base belongs_to :imageable, polymorphic: true + + validates :imageable, presence: true +end + +class Image < ActiveRecord::Base + has_many :pictures, as: :imageable end module Spam; end