From 7b2459a6e83d923572e747b1089b7f7e2de7811d Mon Sep 17 00:00:00 2001 From: Larry Gebhardt Date: Wed, 11 Mar 2015 13:25:39 -0400 Subject: [PATCH 01/26] Remove deprecated `key` method to get ready for 1.0 release. --- lib/jsonapi/association.rb | 10 +--------- lib/jsonapi/resource.rb | 14 -------------- 2 files changed, 1 insertion(+), 23 deletions(-) diff --git a/lib/jsonapi/association.rb b/lib/jsonapi/association.rb index 009d43ae1..bcc98b115 100644 --- a/lib/jsonapi/association.rb +++ b/lib/jsonapi/association.rb @@ -6,15 +6,7 @@ def initialize(name, options={}) @name = name.to_s @options = options @acts_as_set = options.fetch(:acts_as_set, false) == true - @key = options[:key] ? options[:key].to_sym : nil - - if @key.nil? - @foreign_key = options[:foreign_key ] ? options[:foreign_key ].to_sym : nil - else - # :nocov: - warn '[DEPRECATION] `key` is deprecated in associations. Please use `foreign_key` instead.' - # :nocov: - end + @foreign_key = options[:foreign_key ] ? options[:foreign_key ].to_sym : nil end def primary_key diff --git a/lib/jsonapi/resource.rb b/lib/jsonapi/resource.rb index 431cd9c15..7a9a1026d 100644 --- a/lib/jsonapi/resource.rb +++ b/lib/jsonapi/resource.rb @@ -282,13 +282,6 @@ def filter(attr) @_allowed_filters.add(attr.to_sym) end - def key(key) - # :nocov: - warn '[DEPRECATION] `key` is deprecated. Please use `primary_key` instead.' - @_primary_key = key.to_sym - # :nocov: - end - def primary_key(key) @_primary_key = key.to_sym end @@ -456,13 +449,6 @@ def _model_name @_model_name ||= self.name.demodulize.sub(/Resource$/, '') end - def _key - # :nocov: - warn '[DEPRECATION] `_key` is deprecated. Please use `_primary_key` instead.' - _primary_key - # :nocov: - end - def _primary_key @_primary_key ||= :id end From 0ef1cb90b617e6e281e1cc76950bf4aa29a18bf5 Mon Sep 17 00:00:00 2001 From: Larry Gebhardt Date: Wed, 11 Mar 2015 13:27:26 -0400 Subject: [PATCH 02/26] Remove unneeded :nocov: directives --- lib/jsonapi/paginator.rb | 4 +--- lib/jsonapi/resource_controller.rb | 8 +------- 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/lib/jsonapi/paginator.rb b/lib/jsonapi/paginator.rb index 54d25eeb6..5a0a0e057 100644 --- a/lib/jsonapi/paginator.rb +++ b/lib/jsonapi/paginator.rb @@ -4,9 +4,7 @@ def initialize(params) end def apply(relation) - # :nocov: - relation - # :nocov: + # relation end class << self diff --git a/lib/jsonapi/resource_controller.rb b/lib/jsonapi/resource_controller.rb index 44a74da3b..a3f7dbd84 100644 --- a/lib/jsonapi/resource_controller.rb +++ b/lib/jsonapi/resource_controller.rb @@ -52,7 +52,7 @@ def show def show_association association_type = params[:association] - parent_key = params[resource_klass._as_parent_key] + parent_key = resource_klass.verify_key(params[resource_klass._as_parent_key], context) parent_resource = resource_klass.find_by_key(parent_key, context: context) @@ -66,9 +66,7 @@ def show_association render json: serializer.serialize_to_links_hash(parent_resource, association) rescue => e - # :nocov: handle_exceptions(e) - # :nocov: end def create @@ -153,9 +151,7 @@ def ensure_correct_media_type raise JSONAPI::Exceptions::UnsupportedMediaTypeError.new(request.content_type) end rescue => e - # :nocov: handle_exceptions(e) - # :nocov: end def setup_request @@ -165,9 +161,7 @@ def setup_request }) render_errors(@request.errors) unless @request.errors.empty? rescue => e - # :nocov: handle_exceptions(e) - # :nocov: end def setup_response From 3a3d854110ba817d1be5dede2a45f556892f9d05 Mon Sep 17 00:00:00 2001 From: Larry Gebhardt Date: Wed, 11 Mar 2015 13:29:41 -0400 Subject: [PATCH 03/26] Verify key for get_related_resource(s) --- lib/jsonapi/request.rb | 2 +- test/controllers/controller_test.rb | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/jsonapi/request.rb b/lib/jsonapi/request.rb index 10b8a4488..bd3793e19 100644 --- a/lib/jsonapi/request.rb +++ b/lib/jsonapi/request.rb @@ -34,7 +34,7 @@ def setup(params) parse_pagination(params[:page]) when 'get_related_resource', 'get_related_resources' @source_klass = Resource.resource_for(params.require(:source)) - @source_id = params.require(@source_klass._as_parent_key) + @source_id = @source_klass.verify_key(params.require(@source_klass._as_parent_key), @context) parse_fields(params[:fields]) parse_include(params[:include]) parse_filters(params[:filter]) diff --git a/test/controllers/controller_test.rb b/test/controllers/controller_test.rb index 4017d0ad1..cb26f8ccc 100644 --- a/test/controllers/controller_test.rb +++ b/test/controllers/controller_test.rb @@ -1270,6 +1270,12 @@ def test_show_has_many_relationship } } end + + def test_show_has_many_relationship_invalid_id + get :show_association, {post_id: '2,1', association: 'tags'} + assert_response :bad_request + assert_match /2,1 is not a valid value for id/, response.body + end end class TagsControllerTest < ActionController::TestCase From fc54b0ee75743ee18022ae143a5ceb71c7ef35cf Mon Sep 17 00:00:00 2001 From: Larry Gebhardt Date: Wed, 11 Mar 2015 13:30:42 -0400 Subject: [PATCH 04/26] Remove unused code --- test/helpers/hash_helpers.rb | 7 ------- 1 file changed, 7 deletions(-) diff --git a/test/helpers/hash_helpers.rb b/test/helpers/hash_helpers.rb index 579c88b4e..7bc579a26 100644 --- a/test/helpers/hash_helpers.rb +++ b/test/helpers/hash_helpers.rb @@ -1,15 +1,8 @@ module Helpers module HashHelpers - # :nocov: - def assert_hash_contains(exp, act, msg = nil) - msg = message(msg, '') { diff exp, act } - assert(matches_hash?(exp, act), msg) - end - def assert_hash_equals(exp, act, msg = nil) msg = message(msg, '') { diff exp, act } assert(matches_hash?(exp, act, {exact: true}), msg) end - # :nocov: end end From b8ddadf9290ce83bfdca2616a53e50fa722e9cb6 Mon Sep 17 00:00:00 2001 From: Larry Gebhardt Date: Wed, 11 Mar 2015 13:31:13 -0400 Subject: [PATCH 05/26] Remove unreachable error handling --- lib/jsonapi/request.rb | 8 -------- 1 file changed, 8 deletions(-) diff --git a/lib/jsonapi/request.rb b/lib/jsonapi/request.rb index bd3793e19..10ba3c0bc 100644 --- a/lib/jsonapi/request.rb +++ b/lib/jsonapi/request.rb @@ -312,10 +312,6 @@ def parse_params(params, allowed_fields) checked_has_many_associations[param] = association_resource.verify_keys(keys, @context) end end - else - # :nocov: - raise JSONAPI::Exceptions::InvalidLinksObject.new(key) - # :nocov: end end else @@ -365,10 +361,6 @@ def parse_add_association_operation(data, association_type, parent_key) parent_key, association_type, verified_param_set[:has_many].values[0]) - else - # :nocov: - @errors.concat(JSONAPI::Exceptions::InvalidLinksObject.new(:data).errors) - # :nocov: end rescue ActionController::ParameterMissing => e @errors.concat(JSONAPI::Exceptions::ParameterMissing.new(e.param).errors) From a517a1f17b8541e2f025dbc2d4a542b9c7c390da Mon Sep 17 00:00:00 2001 From: Larry Gebhardt Date: Wed, 11 Mar 2015 17:14:16 -0400 Subject: [PATCH 06/26] Move to the default Rails method of transmitting floats and BigDecimals as strings. Rails 4.1 removes the encode_big_decimal_as_string, only allowing strings. See http://stackoverflow.com/a/6132054 for further rational --- test/controllers/controller_test.rb | 8 ++++---- test/test_helper.rb | 2 -- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/test/controllers/controller_test.rb b/test/controllers/controller_test.rb index cb26f8ccc..1c946128b 100644 --- a/test/controllers/controller_test.rb +++ b/test/controllers/controller_test.rb @@ -1396,7 +1396,7 @@ def test_create_expense_entries_underscored assert json_response['data'].is_a?(Hash) assert_equal '3', json_response['data']['links']['employee']['id'] assert_equal 'USD', json_response['data']['links']['iso_currency']['id'] - assert_equal 50.58, json_response['data']['cost'] + assert_equal '50.58', json_response['data']['cost'] delete :destroy, {id: json_response['data']['id']} assert_response :no_content @@ -1425,7 +1425,7 @@ def test_create_expense_entries_camelized_key assert json_response['data'].is_a?(Hash) assert_equal '3', json_response['data']['links']['employee']['id'] assert_equal 'USD', json_response['data']['links']['isoCurrency']['id'] - assert_equal 50.58, json_response['data']['cost'] + assert_equal '50.58', json_response['data']['cost'] delete :destroy, {id: json_response['data']['id']} assert_response :no_content @@ -1454,7 +1454,7 @@ def test_create_expense_entries_dasherized_key assert json_response['data'].is_a?(Hash) assert_equal '3', json_response['data']['links']['employee']['id'] assert_equal 'USD', json_response['data']['links']['iso-currency']['id'] - assert_equal 50.58, json_response['data']['cost'] + assert_equal '50.58', json_response['data']['cost'] delete :destroy, {id: json_response['data']['id']} assert_response :no_content @@ -1790,7 +1790,7 @@ def test_type_formatting assert_equal 'Jane Author', json_response['data']['spouseName'] assert_equal 'First man to run across Antartica.', json_response['data']['bio'] assert_equal 23.89/45.6, json_response['data']['qualityRating'] - assert_equal 47000.56, json_response['data']['salary'] + assert_equal '47000.56', json_response['data']['salary'] assert_equal '2013-08-07T20:25:00.000Z', json_response['data']['dateTimeJoined'] assert_equal '1965-06-30', json_response['data']['birthday'] assert_equal '2000-01-01T20:00:00Z', json_response['data']['bedtime'] diff --git a/test/test_helper.rb b/test/test_helper.rb index 679e5ae22..062bf8d0f 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -32,8 +32,6 @@ class TestApp < Rails::Application config.session_store :cookie_store, key: 'session' config.secret_key_base = 'secret' - ActiveSupport::JSON::Encoding.encode_big_decimal_as_string = false - #Raise errors on unsupported parameters config.action_controller.action_on_unpermitted_parameters = :raise From 71144cb3af40426d453b18fa15f9319e498d541c Mon Sep 17 00:00:00 2001 From: Larry Gebhardt Date: Mon, 16 Mar 2015 21:11:31 -0400 Subject: [PATCH 07/26] Add fixtures. --- test/fixtures/book_comments.yml | 11 ++++ test/fixtures/books.yml | 6 ++ test/fixtures/comments.yml | 17 ++++++ test/fixtures/comments_tags.yml | 20 +++++++ test/fixtures/expense_entries.yml | 13 +++++ test/fixtures/iso_currencies.yml | 17 ++++++ test/fixtures/people.yml | 23 ++++++++ test/fixtures/posts.yml | 96 +++++++++++++++++++++++++++++++ test/fixtures/posts_tags.yml | 59 +++++++++++++++++++ test/fixtures/sections.yml | 8 +++ test/fixtures/tags.yml | 39 +++++++++++++ 11 files changed, 309 insertions(+) create mode 100644 test/fixtures/book_comments.yml create mode 100644 test/fixtures/books.yml create mode 100644 test/fixtures/comments.yml create mode 100644 test/fixtures/comments_tags.yml create mode 100644 test/fixtures/expense_entries.yml create mode 100644 test/fixtures/iso_currencies.yml create mode 100644 test/fixtures/people.yml create mode 100644 test/fixtures/posts.yml create mode 100644 test/fixtures/posts_tags.yml create mode 100644 test/fixtures/sections.yml create mode 100644 test/fixtures/tags.yml diff --git a/test/fixtures/book_comments.yml b/test/fixtures/book_comments.yml new file mode 100644 index 000000000..69d9b8808 --- /dev/null +++ b/test/fixtures/book_comments.yml @@ -0,0 +1,11 @@ +<% comment_id = 0 %> +<% for book_num in 0..4 %> + <% for comment_num in 0..50 %> +book_<%= book_num %>_comment_<%= comment_num %>: + id: <%= comment_id %> + body: This is comment <%= comment_num %> on book <%= book_num %>. + author_id: 1 + book_id: <%= book_num %> + <% comment_id = comment_id + 1 %> + <% end %> +<% end %> \ No newline at end of file diff --git a/test/fixtures/books.yml b/test/fixtures/books.yml new file mode 100644 index 000000000..786e81999 --- /dev/null +++ b/test/fixtures/books.yml @@ -0,0 +1,6 @@ +<% for book_num in 0..999 %> +book_<%= book_num %>: + id: <%= book_num %> + title: Book <%= book_num %> + isbn: 12345-<%= book_num %>-6789 +<% end %> \ No newline at end of file diff --git a/test/fixtures/comments.yml b/test/fixtures/comments.yml new file mode 100644 index 000000000..c656e5039 --- /dev/null +++ b/test/fixtures/comments.yml @@ -0,0 +1,17 @@ +post_1_dumb_post: + id: 1 + post_id: 1 + body: what a dumb post + author_id: 1 + +post_1_i_liked_it: + id: 2 + post_id: 1 + body: i liked it + author_id: 2 + +post_2_thanks_man: + id: 3 + post_id: 2 + body: Thanks man. Great post. But what is JR? + author_id: 2 \ No newline at end of file diff --git a/test/fixtures/comments_tags.yml b/test/fixtures/comments_tags.yml new file mode 100644 index 000000000..d85aaa257 --- /dev/null +++ b/test/fixtures/comments_tags.yml @@ -0,0 +1,20 @@ +post_1_dumb_post_whiny: + comment_id: 1 + tag_id: 2 + +post_1_dumb_post_short: + comment_id: 1 + tag_id: 1 + +post_1_i_liked_it_happy: + comment_id: 2 + tag_id: 4 + +post_1_i_liked_it_short: + comment_id: 2 + tag_id: 1 + +post_2_thanks_man_jr: + comment_id: 3 + tag_id: 5 + diff --git a/test/fixtures/expense_entries.yml b/test/fixtures/expense_entries.yml new file mode 100644 index 000000000..2f640b707 --- /dev/null +++ b/test/fixtures/expense_entries.yml @@ -0,0 +1,13 @@ +entry_1: + id: 1 + currency_code: USD + employee_id: 3 + cost: 12.05 + transaction_date: <%= Date.parse('2014-04-15') %> + +entry_2: + id: 2 + currency_code: USD + employee_id: 3 + cost: 12.06 + transaction_date: <%= Date.parse('2014-04-15') %> \ No newline at end of file diff --git a/test/fixtures/iso_currencies.yml b/test/fixtures/iso_currencies.yml new file mode 100644 index 000000000..590333a22 --- /dev/null +++ b/test/fixtures/iso_currencies.yml @@ -0,0 +1,17 @@ +usd: + code: USD + name: United States Dollar + country_name: United States + minor_unit: cent + +eur: + code: EUR + name: Euro Member Countries + country_name: Euro Member Countries + minor_unit: cent + +cad: + code: CAD + name: Canadian dollar + country_name: Canada + minor_unit: cent \ No newline at end of file diff --git a/test/fixtures/people.yml b/test/fixtures/people.yml new file mode 100644 index 000000000..b6a7186d8 --- /dev/null +++ b/test/fixtures/people.yml @@ -0,0 +1,23 @@ +a: + id: 1 + name: Joe Author + email: joe@xyz.fake + date_joined: <%= DateTime.parse('2013-08-07 20:25:00 UTC +00:00') %> + +b: + id: 2 + name: Fred Reader + email: fred@xyz.fake + date_joined: <%= DateTime.parse('2013-10-31 20:25:00 UTC +00:00') %> + +c: + id: 3 + name: Lazy Author + email: lazy@xyz.fake + date_joined: <%= DateTime.parse('2013-10-31 21:25:00 UTC +00:00') %> + +d: + id: 4 + name: Tag Crazy Author + email: taggy@xyz.fake + date_joined: <%= DateTime.parse('2013-11-30 4:20:00 UTC +00:00') %> \ No newline at end of file diff --git a/test/fixtures/posts.yml b/test/fixtures/posts.yml new file mode 100644 index 000000000..b883bf0da --- /dev/null +++ b/test/fixtures/posts.yml @@ -0,0 +1,96 @@ +post_1: + id: 1 + title: New post + body: A body!!! + author_id: 1 + +post_2: + id: 2 + title: JR Solves your serialization woes! + body: Use JR + author_id: 1 + section_id: 2 + +post_3: + id: 3 + title: Update This Later + body: AAAA + author_id: 3 + +post_4: + id: 4 + title: Delete This Later - Single + body: AAAA + author_id: 3 + +post_5: + id: 5 + title: Delete This Later - Multiple1 + body: AAAA + author_id: 3 + +post_6: + id: 6 + title: Delete This Later - Multiple2 + body: AAAA + author_id: 3 + +post_7: + id: 7 + title: Delete This Later - Single2 + body: AAAA + author_id: 3 + +post_8: + id: 8 + title: Delete This Later - Multiple2-1 + body: AAAA + author_id: 3 + +post_9: + id: 9 + title: Delete This Later - Multiple2-2 + body: AAAA + author_id: 3 + +post_10: + id: 10 + title: Update This Later - Multiple + body: AAAA + author_id: 3 + +post_11: + id: 11 + title: JR How To + body: Use JR to write API apps + author_id: 1 + +post_12: + id: 12 + title: Tagged up post 1 + body: AAAA + author_id: 4 + +post_13: + id: 13 + title: Tagged up post 2 + body: BBBB + author_id: 4 + +post_14: + id: 14 + title: A First Post + body: A First Post!!!!!!!!! + author_id: 3 + +post_15: + id: 15 + title: AAAA First Post + body: First!!!!!!!!! + author_id: 3 + +post_16: + id: 16 + title: SDFGH + body: Not First!!!! + author_id: 3 \ No newline at end of file diff --git a/test/fixtures/posts_tags.yml b/test/fixtures/posts_tags.yml new file mode 100644 index 000000000..2b37708d1 --- /dev/null +++ b/test/fixtures/posts_tags.yml @@ -0,0 +1,59 @@ +post_1_short: + post_id: 1 + tag_id: 1 + +post_1_whiny: + post_id: 1 + tag_id: 2 + +post_1_grumpy: + post_id: 1 + tag_id: 3 + +post_2_jr: + post_id: 2 + tag_id: 5 + +post_11_jr: + post_id: 11 + tag_id: 5 + +post_12_silly: + post_id: 12 + tag_id: 6 + +post_12_sleepy: + post_id: 12 + tag_id: 7 + +post_12_goofy: + post_id: 12 + tag_id: 8 + +post_12_wacky: + post_id: 12 + tag_id: 9 + +post_13_silly: + post_id: 13 + tag_id: 6 + +post_13_sleepy: + post_id: 13 + tag_id: 7 + +post_13_goofy: + post_id: 13 + tag_id: 8 + +post_13_wacky: + post_id: 13 + tag_id: 9 + +post_14_whiny: + post_id: 14 + tag_id: 2 + +post_14_grumpy: + post_id: 14 + tag_id: 3 diff --git a/test/fixtures/sections.yml b/test/fixtures/sections.yml new file mode 100644 index 000000000..f22a750a2 --- /dev/null +++ b/test/fixtures/sections.yml @@ -0,0 +1,8 @@ +javascript: + id: 1 + name: javascript + +ruby: + id: 2 + name: ruby + diff --git a/test/fixtures/tags.yml b/test/fixtures/tags.yml new file mode 100644 index 000000000..a3a0bd639 --- /dev/null +++ b/test/fixtures/tags.yml @@ -0,0 +1,39 @@ +short_tag: + id: 1 + name: short + +whiny_tag: + id: 2 + name: whiny + +grumpy_tag: + id: 3 + name: grumpy + +happy_tag: + id: 4 + name: happy + +jr_tag: + id: 5 + name: JR + +silly_tag: + id: 6 + name: silly + +sleepy_tag: + id: 7 + name: sleepy + +goofy_tag: + id: 8 + name: goofy + +wacky_tag: + id: 9 + name: wacky + +bad_tag: + id: 10 + name: bad \ No newline at end of file From c5b7cd0ecb7ee536ebab17c891e7aff328721af2 Mon Sep 17 00:00:00 2001 From: Larry Gebhardt Date: Mon, 16 Mar 2015 21:13:00 -0400 Subject: [PATCH 08/26] Cleanup `require` statements --- test/fixtures/active_record.rb | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/test/fixtures/active_record.rb b/test/fixtures/active_record.rb index 8b3aa1eff..efd00ac50 100644 --- a/test/fixtures/active_record.rb +++ b/test/fixtures/active_record.rb @@ -1,9 +1,5 @@ require 'active_record' -require 'jsonapi/resource_controller' -require 'jsonapi/resource' -require 'jsonapi/exceptions' -require 'rails' -require 'rails/all' +require 'jsonapi-resources' ActiveSupport::Inflector.inflections(:en) do |inflect| inflect.uncountable 'preferences' From 7595d8d83c4453f265e6cd81e492c5a57f0dd07e Mon Sep 17 00:00:00 2001 From: Larry Gebhardt Date: Mon, 16 Mar 2015 21:14:05 -0400 Subject: [PATCH 09/26] Remove test data created by object instantiation --- test/fixtures/active_record.rb | 149 +-------------------------------- 1 file changed, 2 insertions(+), 147 deletions(-) diff --git a/test/fixtures/active_record.rb b/test/fixtures/active_record.rb index efd00ac50..ead208e54 100644 --- a/test/fixtures/active_record.rb +++ b/test/fixtures/active_record.rb @@ -738,141 +738,7 @@ class BadlyNamedAttributesResource < JSONAPI::Resource end warn 'end testing Name Collisions' -### DATA -javascript = Section.create(name: 'javascript') -ruby = Section.create(name: 'ruby') - -a = Person.create(name: 'Joe Author', - email: 'joe@xyz.fake', - date_joined: DateTime.parse('2013-08-07 20:25:00 UTC +00:00')) - -b = Person.create(name: 'Fred Reader', - email: 'fred@xyz.fake', - date_joined: DateTime.parse('2013-10-31 20:25:00 UTC +00:00')) - -c = Person.create(name: 'Lazy Author', - email: 'lazy@xyz.fake', - date_joined: DateTime.parse('2013-10-31 21:25:00 UTC +00:00')) - -d = Person.create(name: 'Tag Crazy Author', - email: 'taggy@xyz.fake', - date_joined: DateTime.parse('2013-11-30 4:20:00 UTC +00:00')) - -short_tag = Tag.create(name: 'short') -whiny_tag = Tag.create(name: 'whiny') -grumpy_tag = Tag.create(name: 'grumpy') -happy_tag = Tag.create(name: 'happy') -jr_tag = Tag.create(name: 'JR') - -silly_tag = Tag.create(name: 'silly') -sleepy_tag = Tag.create(name: 'sleepy') -goofy_tag = Tag.create(name: 'goofy') -wacky_tag = Tag.create(name: 'wacky') - -# id:1 -Post.create(title: 'New post', - body: 'A body!!!', - author_id: a.id).tap do |post| - - post.tags.concat short_tag, whiny_tag, grumpy_tag - - post.comments.create(body: 'what a dumb post', author_id: a.id, post_id: post.id).tap do |comment| - comment.tags.concat whiny_tag, short_tag - end - - post.comments.create(body: 'i liked it', author_id: b.id, post_id: post.id).tap do |comment| - comment.tags.concat happy_tag, short_tag - end -end - -# id:2 -Post.create(title: 'JR Solves your serialization woes!', - body: 'Use JR', - author_id: a.id, - section: Section.create(name: 'ruby')).tap do |post| - - post.tags.concat jr_tag - - post.comments.create(body: 'Thanks man. Great post. But what is JR?', author_id: b.id, post_id: post.id).tap do |comment| - comment.tags.concat jr_tag - end -end - -# id:3 -Post.create(title: 'Update This Later', - body: 'AAAA', - author_id: c.id) - -# id:4 -Post.create(title: 'Delete This Later - Single', - body: 'AAAA', - author_id: c.id) - -# id:5 -Post.create(title: 'Delete This Later - Multiple1', - body: 'AAAA', - author_id: c.id) - -# id:6 -Post.create(title: 'Delete This Later - Multiple2', - body: 'AAAA', - author_id: c.id) - -# id:7 -Post.create(title: 'Delete This Later - Single2', - body: 'AAAA', - author_id: c.id) - -# id:8 -Post.create(title: 'Delete This Later - Multiple2-1', - body: 'AAAA', - author_id: c.id) - -# id:9 -Post.create(title: 'Delete This Later - Multiple2-2', - body: 'AAAA', - author_id: c.id) - -# id:9 -Post.create(title: 'Update This Later - Multiple', - body: 'AAAA', - author_id: c.id) - -# id:10 -Post.create(title: 'JR How To', - body: 'Use JR to write API apps', - author_id: a.id).tap do |post| - post.tags.concat jr_tag -end - -IsoCurrency.create(code: 'USD', name: 'United States Dollar', country_name: 'United States', minor_unit: 'cent') -IsoCurrency.create(code: 'EUR', name: 'Euro Member Countries', country_name: 'Euro Member Countries', minor_unit: 'cent') -IsoCurrency.create(code: 'CAD', name: 'Canadian dollar', country_name: 'Canada', minor_unit: 'cent') - -ExpenseEntry.create(currency_code: 'USD', - employee_id: c.id, - cost: '12.05', - transaction_date: Date.parse('2014-04-15')) - -ExpenseEntry.create(currency_code: 'USD', - employee_id: c.id, - cost: '12.06', - transaction_date: Date.parse('2014-04-15')) - -# id:11 -Post.create(title: 'Tagged up post 1', - body: 'AAAA', - author_id: d.id, - tag_ids: [6,7,8,9] - ) - -# id:12 -Post.create(title: 'Tagged up post 2', - body: 'BBBB', - author_id: d.id, - tag_ids: [6,7,8,9] -) - +### PORO DATA gas_giant = PlanetType.create(name: 'Gas Giant') planetoid = PlanetType.create(name: 'Planetoid') terrestrial = PlanetType.create(name: 'Terrestrial') @@ -902,15 +768,4 @@ class BadlyNamedAttributesResource < JSONAPI::Resource bedtime: Time.parse('2000-01-01 20:00:00 UTC +00:00'), photo: "abc", cool: false -) - -for book_num in 0..999 - Book.create(title: "Book #{book_num}", isbn: "12345-#{book_num}-67890") do |book| - book.save - if book_num < 5 - for comment_num in 0..50 - book.book_comments.create(body: "This is comment #{comment_num} on book #{book_num}.", author_id: a.id, book_id: book.id) - end - end - end -end +) \ No newline at end of file From 91beece2d34b79a4784a7a60a855188f4822a5ed Mon Sep 17 00:00:00 2001 From: Larry Gebhardt Date: Mon, 16 Mar 2015 21:26:11 -0400 Subject: [PATCH 10/26] Add null false to timestamps for rails 4.1 compatibility --- test/fixtures/active_record.rb | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/test/fixtures/active_record.rb b/test/fixtures/active_record.rb index ead208e54..7dcc3d908 100644 --- a/test/fixtures/active_record.rb +++ b/test/fixtures/active_record.rb @@ -12,7 +12,7 @@ t.string :email t.datetime :date_joined t.belongs_to :preferences - t.timestamps + t.timestamps null: false end create_table :posts, force: true do |t| @@ -20,14 +20,14 @@ t.text :body t.integer :author_id t.belongs_to :section, index: true - t.timestamps + t.timestamps null: false end create_table :comments, force: true do |t| t.text :body t.belongs_to :post, index: true t.integer :author_id - t.timestamps + t.timestamps null: false end create_table :tags, force: true do |t| @@ -52,7 +52,7 @@ t.string :name t.string :country_name t.string :minor_unit - t.timestamps + t.timestamps null: false end add_index :iso_currencies, :code, unique: true @@ -111,7 +111,7 @@ t.text :body t.belongs_to :book, index: true t.integer :author_id - t.timestamps + t.timestamps null: false end end From 816469e3ea83093401ba4dd3b8681232c7168ecb Mon Sep 17 00:00:00 2001 From: Larry Gebhardt Date: Mon, 16 Mar 2015 21:27:27 -0400 Subject: [PATCH 11/26] Default to rails 4.2 --- Gemfile | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Gemfile b/Gemfile index aecbc7c92..8f401d330 100644 --- a/Gemfile +++ b/Gemfile @@ -10,11 +10,14 @@ platforms :jruby do gem 'activerecord-jdbcsqlite3-adapter' end -version = ENV['RAILS_VERSION'] || '4.0.4' +version = ENV['RAILS_VERSION'] || 'default' rails = case version when 'master' {:github => 'rails/rails'} + when 'default' + '>= 4.2' else "~> #{version}" end gem 'rails', rails +gem 'minitest' From 1dae5666ff8b64dbf382cbf4f333c24503872004 Mon Sep 17 00:00:00 2001 From: Larry Gebhardt Date: Mon, 16 Mar 2015 21:28:24 -0400 Subject: [PATCH 12/26] Adds resource_controller to the default required files --- lib/jsonapi-resources.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/jsonapi-resources.rb b/lib/jsonapi-resources.rb index cc0588fee..735a08b0d 100644 --- a/lib/jsonapi-resources.rb +++ b/lib/jsonapi-resources.rb @@ -1,4 +1,5 @@ require 'jsonapi/resource' +require 'jsonapi/resource_controller' require 'jsonapi/resources/version' require 'jsonapi/configuration' require 'jsonapi/paginator' From 72c89dbf1e007c00a70599885221fed862e8909a Mon Sep 17 00:00:00 2001 From: Larry Gebhardt Date: Mon, 16 Mar 2015 21:31:07 -0400 Subject: [PATCH 13/26] Remove duplicated minitest gem reference --- Gemfile | 1 - 1 file changed, 1 deletion(-) diff --git a/Gemfile b/Gemfile index 8f401d330..1bba46ea9 100644 --- a/Gemfile +++ b/Gemfile @@ -20,4 +20,3 @@ rails = case version "~> #{version}" end gem 'rails', rails -gem 'minitest' From 256dc9b37821ef24712941ab71cae2dffcd8ef1a Mon Sep 17 00:00:00 2001 From: Larry Gebhardt Date: Mon, 16 Mar 2015 21:31:59 -0400 Subject: [PATCH 14/26] Simplify require statements --- test/test_helper.rb | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/test/test_helper.rb b/test/test_helper.rb index 062bf8d0f..924d5cf74 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -7,14 +7,9 @@ end end -require 'minitest/autorun' -require 'minitest/spec' require 'rails/all' - -require 'jsonapi/routing_ext' -require 'jsonapi/configuration' -require 'jsonapi/formatter' -require 'jsonapi/mime_types' +require 'rails/test_help' +require 'jsonapi-resources' require File.expand_path('../helpers/value_matchers', __FILE__) require File.expand_path('../helpers/hash_helpers', __FILE__) From 8a32ffe20f16fa3892141685e3b346b1c5172799 Mon Sep 17 00:00:00 2001 From: Larry Gebhardt Date: Tue, 17 Mar 2015 07:43:09 -0400 Subject: [PATCH 15/26] Output the Rails version used for the test run --- test/test_helper.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/test_helper.rb b/test/test_helper.rb index 924d5cf74..523022d92 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -21,6 +21,8 @@ config.json_key_format = :camelized_key end +puts "Testing With RAILS VERSION #{Rails.version}" + class TestApp < Rails::Application config.eager_load = false config.root = File.dirname(__FILE__) From f3841e0da74189efa981d154634aa22554ed2503 Mon Sep 17 00:00:00 2001 From: Larry Gebhardt Date: Tue, 17 Mar 2015 07:44:48 -0400 Subject: [PATCH 16/26] Comments about running options --- test/test_helper.rb | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/test/test_helper.rb b/test/test_helper.rb index 523022d92..f07230eac 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -1,7 +1,10 @@ require 'simplecov' -# To run tests with coverage +# To run tests with coverage: # COVERAGE=true rake test +# To Switch rails versions and run a particular test order: +# export RAILS_VERSION=4.2; bundle update rails; bundle exec rake TESTOPTS="--seed=39333" test + if ENV['COVERAGE'] SimpleCov.start do end From 3a9d018f1d95b39ea69ca86ec2dfa01752ee496d Mon Sep 17 00:00:00 2001 From: Larry Gebhardt Date: Tue, 17 Mar 2015 07:45:40 -0400 Subject: [PATCH 17/26] Support Rails 4.1 and higher --- test/test_helper.rb | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/test/test_helper.rb b/test/test_helper.rb index f07230eac..61ceb54ae 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -36,11 +36,31 @@ class TestApp < Rails::Application config.action_controller.action_on_unpermitted_parameters = :raise config.active_record.schema_format = :none + config.active_support.test_order = :random + + # Turn off millisecond precision to maintain Rails 4.0 and 4.1 compatibility in test results + ActiveSupport::JSON::Encoding.time_precision = 0 if Rails::VERSION::MAJOR >= 4 && Rails::VERSION::MINOR >= 1 +end + +# Patch RAILS 4.0 to not use millisecond precision +if Rails::VERSION::MAJOR >= 4 && Rails::VERSION::MINOR < 1 + module ActiveSupport + class TimeWithZone + def as_json(options = nil) + if ActiveSupport::JSON::Encoding.use_standard_json_time_format + xmlschema + else + %(#{time.strftime("%Y/%m/%d %H:%M:%S")} #{formatted_offset(false)}) + end + end + end + end end TestApp.initialize! require File.expand_path('../fixtures/active_record', __FILE__) + JSONAPI.configuration.route_format = :underscored_route TestApp.routes.draw do jsonapi_resources :people @@ -127,18 +147,30 @@ class TestApp < Rails::Application end end -class MiniTest::Unit::TestCase +# Ensure backward compatibility with Minitest 4 +Minitest::Test = MiniTest::Unit::TestCase unless defined?(Minitest::Test) + +class Minitest::Test include Helpers::HashHelpers include Helpers::ValueMatchers include Helpers::FunctionalHelpers end class ActiveSupport::TestCase + self.fixture_path = "#{Rails.root}/fixtures" + # self.use_transactional_fixtures = false + fixtures :all setup do @routes = TestApp.routes end end +class ActionDispatch::IntegrationTest + self.fixture_path = "#{Rails.root}/fixtures" + # self.use_transactional_fixtures = false + fixtures :all +end + class UpperCamelizedKeyFormatter < JSONAPI::KeyFormatter class << self def format(key) From 829718861076ed0c3e54fcc6d91430ff401935c2 Mon Sep 17 00:00:00 2001 From: Larry Gebhardt Date: Tue, 17 Mar 2015 07:47:30 -0400 Subject: [PATCH 18/26] Rework tests to avoid interactions. We still need to figure out why there are some interactions between some tests. --- test/controllers/controller_test.rb | 55 +++++++++++-------- test/integration/requests/request_test.rb | 16 +++--- .../operation/operations_processor_test.rb | 3 +- test/unit/resource/resource_test.rb | 3 +- test/unit/serializer/serializer_test.rb | 5 +- 5 files changed, 43 insertions(+), 39 deletions(-) diff --git a/test/controllers/controller_test.rb b/test/controllers/controller_test.rb index 1c946128b..a8b6d7f71 100644 --- a/test/controllers/controller_test.rb +++ b/test/controllers/controller_test.rb @@ -1,5 +1,4 @@ require File.expand_path('../../test_helper', __FILE__) -require File.expand_path('../../fixtures/active_record', __FILE__) def set_content_type_header! @request.headers['Content-Type'] = JSONAPI::MEDIA_TYPE @@ -178,7 +177,7 @@ def test_sorting_asc get :index, {sort: '+title'} assert_response :success - assert_equal "Delete This Later - Multiple2-1", json_response['data'][0]['title'] + assert_equal "A First Post", json_response['data'][0]['title'] end def test_sorting_desc @@ -192,7 +191,7 @@ def test_sorting_by_multiple_fields get :index, {sort: '+title,+body'} assert_response :success - assert_equal '8', json_response['data'][0]['id'] + assert_equal '14', json_response['data'][0]['id'] end def test_invalid_sort_param @@ -615,13 +614,13 @@ def test_update_remove_links def test_update_relationship_has_one set_content_type_header! ruby = Section.find_by(name: 'ruby') - post_object = Post.find(3) + post_object = Post.find(4) assert_not_equal ruby.id, post_object.section_id - put :update_association, {post_id: 3, association: 'section', data: {type: 'sections', id: "#{ruby.id}"}} + put :update_association, {post_id: 4, association: 'section', data: {type: 'sections', id: "#{ruby.id}"}} assert_response :no_content - post_object = Post.find(3) + post_object = Post.find(4) assert_equal ruby.id, post_object.section_id end @@ -872,12 +871,12 @@ def test_update_relationship_has_many_missing_tags def test_delete_relationship_has_many set_content_type_header! - put :update_association, {post_id: 9, association: 'tags', data: {type: 'tags', ids: [2, 3]}} + put :update_association, {post_id: 14, association: 'tags', data: {type: 'tags', ids: [2, 3]}} assert_response :no_content - p = Post.find(9) + p = Post.find(14) assert_equal [2, 3], p.tag_ids - delete :destroy_association, {post_id: 9, association: 'tags', keys: '3'} + delete :destroy_association, {post_id: 14, association: 'tags', keys: '3'} p.reload assert_response :no_content @@ -886,12 +885,12 @@ def test_delete_relationship_has_many def test_delete_relationship_has_many_does_not_exist set_content_type_header! - put :update_association, {post_id: 9, association: 'tags', data: {type: 'tags', ids: [2, 3]}} + put :update_association, {post_id: 14, association: 'tags', data: {type: 'tags', ids: [2, 3]}} assert_response :no_content - p = Post.find(9) + p = Post.find(14) assert_equal [2, 3], p.tag_ids - delete :destroy_association, {post_id: 9, association: 'tags', keys: '4'} + delete :destroy_association, {post_id: 14, association: 'tags', keys: '4'} p.reload assert_response :not_found @@ -900,12 +899,12 @@ def test_delete_relationship_has_many_does_not_exist def test_delete_relationship_has_many_with_empty_data set_content_type_header! - put :update_association, {post_id: 9, association: 'tags', data: {type: 'tags', ids: [2, 3]}} + put :update_association, {post_id: 14, association: 'tags', data: {type: 'tags', ids: [2, 3]}} assert_response :no_content - p = Post.find(9) + p = Post.find(14) assert_equal [2, 3], p.tag_ids - put :update_association, {post_id: 9, association: 'tags', data: [] } + put :update_association, {post_id: 14, association: 'tags', data: [] } p.reload assert_response :no_content @@ -1045,7 +1044,7 @@ def test_update_multiple put :update, { - id: [3, 9], + id: [3, 16], data: [ { type: 'posts', @@ -1058,7 +1057,7 @@ def test_update_multiple }, { type: 'posts', - id: 9, + id: 16, title: 'A great new Post ASDFG', links: { section: {type: 'sections', id: "#{javascript.id}"}, @@ -1080,7 +1079,7 @@ def test_update_multiple assert_equal json_response['data'][1]['links']['author']['id'], '3' assert_equal json_response['data'][1]['links']['section']['id'], javascript.id.to_s assert_equal json_response['data'][1]['title'], 'A great new Post ASDFG' - assert_equal json_response['data'][1]['body'], 'AAAA' + assert_equal json_response['data'][1]['body'], 'Not First!!!!' assert_equal json_response['data'][1]['links']['tags']['ids'], ['3', '4'] end @@ -1259,14 +1258,14 @@ def test_show_has_one_relationship end def test_show_has_many_relationship - get :show_association, {post_id: '1', association: 'tags'} + get :show_association, {post_id: '2', association: 'tags'} assert_response :success assert_hash_equals json_response, {data: { type: 'tags', - ids: ['1', '2', '3'], - self: 'http://test.host/posts/1/links/tags', - related: 'http://test.host/posts/1/tags' + ids: ['5'], + self: 'http://test.host/posts/2/links/tags', + related: 'http://test.host/posts/2/tags' } } end @@ -1312,7 +1311,7 @@ def test_tags_show_multiple_with_nonexistent_ids_at_the_beginning end class ExpenseEntriesControllerTest < ActionController::TestCase - def after_teardown + def setup JSONAPI.configuration.json_key_format = :camelized_key end @@ -1552,6 +1551,10 @@ def test_currencies_json_key_custom_json_key_filter end class PeopleControllerTest < ActionController::TestCase + def setup + JSONAPI.configuration.json_key_format = :camelized_key + end + def test_create_validations set_content_type_header! post :create, @@ -1783,6 +1786,10 @@ def test_create_simple_namespaced end class FactsControllerTest < ActionController::TestCase + def setup + JSONAPI.configuration.json_key_format = :camelized_key + end + def test_type_formatting get :show, {id: '1'} assert_response :success @@ -1791,7 +1798,7 @@ def test_type_formatting assert_equal 'First man to run across Antartica.', json_response['data']['bio'] assert_equal 23.89/45.6, json_response['data']['qualityRating'] assert_equal '47000.56', json_response['data']['salary'] - assert_equal '2013-08-07T20:25:00.000Z', json_response['data']['dateTimeJoined'] + assert_equal '2013-08-07T20:25:00Z', json_response['data']['dateTimeJoined'] assert_equal '1965-06-30', json_response['data']['birthday'] assert_equal '2000-01-01T20:00:00Z', json_response['data']['bedtime'] assert_equal 'abc', json_response['data']['photo'] diff --git a/test/integration/requests/request_test.rb b/test/integration/requests/request_test.rb index 2f4d9c8be..1e1234909 100644 --- a/test/integration/requests/request_test.rb +++ b/test/integration/requests/request_test.rb @@ -269,7 +269,7 @@ def test_pagination_related_resources_link assert_equal 200, status assert_equal 2, json_response['data'].size assert_equal 'http://www.example.com/api/v2/books/1/book_comments', - json_response['data'][0]['links']['book_comments']['related'] + json_response['data'][1]['links']['book_comments']['related'] end def test_pagination_related_resources_data @@ -278,7 +278,7 @@ def test_pagination_related_resources_data get '/api/v2/books/1/book_comments?page[limit]=10' assert_equal 200, status assert_equal 10, json_response['data'].size - assert_equal 'This is comment 9 on book 0.', json_response['data'][9]['body'] + assert_equal 'This is comment 9 on book 1.', json_response['data'][9]['body'] end def test_pagination_related_resources_data_includes @@ -287,7 +287,7 @@ def test_pagination_related_resources_data_includes get '/api/v2/books/1/book_comments?page[limit]=10&include=author,book' assert_equal 200, status assert_equal 10, json_response['data'].size - assert_equal 'This is comment 9 on book 0.', json_response['data'][9]['body'] + assert_equal 'This is comment 9 on book 1.', json_response['data'][9]['body'] end def test_flow_self @@ -329,10 +329,10 @@ def test_flow_link_has_many_self_link def test_flow_link_has_many_self_link_put get '/posts' assert_equal 200, status - post_1 = json_response['data'][0] + post_1 = json_response['data'][4] post post_1['links']['tags']['self'], - {'data' => {'type' => 'tags', 'ids' => ['5']}}.to_json, + {'data' => {'type' => 'tags', 'ids' => ['10']}}.to_json, "CONTENT_TYPE" => JSONAPI::MEDIA_TYPE assert_equal 204, status @@ -341,9 +341,9 @@ def test_flow_link_has_many_self_link_put assert_equal 200, status assert_hash_equals(json_response, {'data' => { - 'self' => 'http://www.example.com/posts/1/links/tags', - 'related' => 'http://www.example.com/posts/1/tags', - 'type' => 'tags', 'ids'=>['1', '2', '3', '5'] + 'self' => 'http://www.example.com/posts/5/links/tags', + 'related' => 'http://www.example.com/posts/5/tags', + 'type' => 'tags', 'ids'=>['10'] } }) end diff --git a/test/unit/operation/operations_processor_test.rb b/test/unit/operation/operations_processor_test.rb index 21fc4fdb2..43c378007 100644 --- a/test/unit/operation/operations_processor_test.rb +++ b/test/unit/operation/operations_processor_test.rb @@ -1,5 +1,4 @@ require File.expand_path('../../../test_helper', __FILE__) -require File.expand_path('../../../fixtures/active_record', __FILE__) require 'jsonapi/operation' require 'jsonapi/operation_result' @@ -55,7 +54,7 @@ def log_after_operations end end -class OperationsProcessorTest < MiniTest::Unit::TestCase +class OperationsProcessorTest < Minitest::Test def setup betax = Planet.find(5) betay = Planet.find(6) diff --git a/test/unit/resource/resource_test.rb b/test/unit/resource/resource_test.rb index ee78631d7..b5d6a30e4 100644 --- a/test/unit/resource/resource_test.rb +++ b/test/unit/resource/resource_test.rb @@ -1,5 +1,4 @@ require File.expand_path('../../../test_helper', __FILE__) -require File.expand_path('../../../fixtures/active_record', __FILE__) class ArticleResource < JSONAPI::Resource model_name 'Post' @@ -40,7 +39,7 @@ def records_for(association_name, context) end end -class ResourceTest < MiniTest::Unit::TestCase +class ResourceTest < ActiveSupport::TestCase def setup @post = Post.first end diff --git a/test/unit/serializer/serializer_test.rb b/test/unit/serializer/serializer_test.rb index 75d473b26..d2f04f5c9 100644 --- a/test/unit/serializer/serializer_test.rb +++ b/test/unit/serializer/serializer_test.rb @@ -1,9 +1,8 @@ require File.expand_path('../../../test_helper', __FILE__) -require File.expand_path('../../../fixtures/active_record', __FILE__) require 'jsonapi-resources' require 'json' -class SerializerTest < MiniTest::Unit::TestCase +class SerializerTest < ActionDispatch::IntegrationTest def setup @post = Post.find(1) @fred = Person.find_by(name: 'Fred Reader') @@ -663,7 +662,7 @@ def test_serializer_array_of_resources self: '/posts/2/links/section', related: '/posts/2/section', type: 'sections', - id: '3' + id: '2' }, author: { self: '/posts/2/links/author', From 2001a2bf2d349bfd2eddb8d937d6cc5874be29f3 Mon Sep 17 00:00:00 2001 From: Larry Gebhardt Date: Tue, 17 Mar 2015 07:48:42 -0400 Subject: [PATCH 19/26] Switch to file based database for tests. --- .gitignore | 4 +++- test/config/database.yml | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index fffdede3a..44b605873 100644 --- a/.gitignore +++ b/.gitignore @@ -17,4 +17,6 @@ test/tmp test/version_tmp tmp coverage -test/log \ No newline at end of file +test/log +test_db +test_db-journal \ No newline at end of file diff --git a/test/config/database.yml b/test/config/database.yml index 85b7ead63..122535f3e 100644 --- a/test/config/database.yml +++ b/test/config/database.yml @@ -1,5 +1,6 @@ test: adapter: sqlite3 - database: ":memory:" + database: "test_db" +# database: ":memory:" pool: 5 timeout: 5000 From 207d7b479f0c92f7e29364f76c7ed033e33771ed Mon Sep 17 00:00:00 2001 From: Larry Gebhardt Date: Tue, 17 Mar 2015 09:03:10 -0400 Subject: [PATCH 20/26] Add travis support for multiple rails versions --- .travis.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.travis.yml b/.travis.yml index 61ce935a6..aba4f90f5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,8 @@ language: ruby +env: + - "RAILS_VERSION=4.0" + - "RAILS_VERSION=4.1" + - "RAILS_VERSION=4.2" rvm: - 2.0 - 2.1 From ccbb55ff78f668ee6e1cda31959a5db91f4a29fd Mon Sep 17 00:00:00 2001 From: Larry Gebhardt Date: Tue, 17 Mar 2015 10:46:04 -0400 Subject: [PATCH 21/26] Move facts and preferences sample data to fixtures --- test/fixtures/active_record.rb | 15 +-------------- test/fixtures/facts.yml | 11 +++++++++++ test/fixtures/people.yml | 1 + test/fixtures/preferences.yml | 18 ++++++++++++++++++ 4 files changed, 31 insertions(+), 14 deletions(-) create mode 100644 test/fixtures/facts.yml create mode 100644 test/fixtures/preferences.yml diff --git a/test/fixtures/active_record.rb b/test/fixtures/active_record.rb index 7dcc3d908..697b57ccb 100644 --- a/test/fixtures/active_record.rb +++ b/test/fixtures/active_record.rb @@ -755,17 +755,4 @@ class BadlyNamedAttributesResource < JSONAPI::Resource betax = Planet.create(name: 'Beta X', description: 'Newly discovered Planet X', planet_type_id: unknown.id) betay = Planet.create(name: 'Beta X', description: 'Newly discovered Planet Y', planet_type_id: unknown.id) betaz = Planet.create(name: 'Beta X', description: 'Newly discovered Planet Z', planet_type_id: unknown.id) -betaw = Planet.create(name: 'Beta W', description: 'Newly discovered Planet W') - -preference = Preferences.create - -fact = Fact.create(spouse_name: 'Jane Author', - bio: 'First man to run across Antartica.', - quality_rating: 23.89/45.6, - salary: BigDecimal('47000.56'), - date_time_joined: DateTime.parse('2013-08-07 20:25:00 UTC +00:00'), - birthday: Date.parse('1965-06-30'), - bedtime: Time.parse('2000-01-01 20:00:00 UTC +00:00'), - photo: "abc", - cool: false -) \ No newline at end of file +betaw = Planet.create(name: 'Beta W', description: 'Newly discovered Planet W') \ No newline at end of file diff --git a/test/fixtures/facts.yml b/test/fixtures/facts.yml new file mode 100644 index 000000000..c387b08fb --- /dev/null +++ b/test/fixtures/facts.yml @@ -0,0 +1,11 @@ +fact_1: + id: 1 + spouse_name: Jane Author + bio: First man to run across Antartica. + quality_rating: <%= 23.89/45.6 %> + salary: 47000.56 + date_time_joined: 2013-08-07 20:25:00 UTC +00:00 + birthday: 1965-06-30 + bedtime: 2000-01-01 20:00:00 UTC +00:00 + photo: abc + cool: false diff --git a/test/fixtures/people.yml b/test/fixtures/people.yml index b6a7186d8..cdf0a5bf6 100644 --- a/test/fixtures/people.yml +++ b/test/fixtures/people.yml @@ -3,6 +3,7 @@ a: name: Joe Author email: joe@xyz.fake date_joined: <%= DateTime.parse('2013-08-07 20:25:00 UTC +00:00') %> + preferences_id: 1 b: id: 2 diff --git a/test/fixtures/preferences.yml b/test/fixtures/preferences.yml new file mode 100644 index 000000000..a094fd45f --- /dev/null +++ b/test/fixtures/preferences.yml @@ -0,0 +1,18 @@ +a: + id: 1 + person_id: + advanced_mode: false + +b: + id: 2 + person_id: + advanced_mode: false +c: + id: 3 + person_id: + advanced_mode: false + +d: + id: 4 + person_id: + advanced_mode: false From 5d3ffaf0ccda257fa38f2806c395d96bad4e53f4 Mon Sep 17 00:00:00 2001 From: Larry Gebhardt Date: Tue, 17 Mar 2015 10:46:20 -0400 Subject: [PATCH 22/26] Spelling --- test/unit/resource/resource_test.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/unit/resource/resource_test.rb b/test/unit/resource/resource_test.rb index b5d6a30e4..e740d8b98 100644 --- a/test/unit/resource/resource_test.rb +++ b/test/unit/resource/resource_test.rb @@ -62,7 +62,7 @@ def test_class_attributes assert_equal(attrs.keys.size, 3) end - def test_class_assosications + def test_class_associations associations = CatResource._associations assert_kind_of(Hash, associations) assert_equal(associations.size, 2) From d48030446a38bfa58fcf9cced9a1ebc63c2a1616 Mon Sep 17 00:00:00 2001 From: Larry Gebhardt Date: Tue, 17 Mar 2015 10:46:48 -0400 Subject: [PATCH 23/26] Single quotes for consistency --- test/unit/serializer/serializer_test.rb | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/test/unit/serializer/serializer_test.rb b/test/unit/serializer/serializer_test.rb index d2f04f5c9..6957fd48b 100644 --- a/test/unit/serializer/serializer_test.rb +++ b/test/unit/serializer/serializer_test.rb @@ -168,10 +168,10 @@ def test_serializer_include related: '/people/1/posts' }, preferences: { - self: "/people/1/links/preferences", - related: "/people/1/preferences", - type: "preferences", - id: "1" + self: '/people/1/links/preferences', + related: '/people/1/preferences', + type: 'preferences', + id: '1' } } } @@ -233,10 +233,10 @@ def test_serializer_key_format related: '/people/1/posts' }, preferences: { - self: "/people/1/links/preferences", - related: "/people/1/preferences", - type: "preferences", - id: "1" + self: '/people/1/links/preferences', + related: '/people/1/preferences', + type: 'preferences', + id: '1' } } } From c9ff67753445ad4969b71c01c70560a9c800ee95 Mon Sep 17 00:00:00 2001 From: Larry Gebhardt Date: Tue, 17 Mar 2015 10:47:58 -0400 Subject: [PATCH 24/26] Cleanup --- test/test_helper.rb | 2 -- 1 file changed, 2 deletions(-) diff --git a/test/test_helper.rb b/test/test_helper.rb index 61ceb54ae..3ae17ed87 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -158,7 +158,6 @@ class Minitest::Test class ActiveSupport::TestCase self.fixture_path = "#{Rails.root}/fixtures" - # self.use_transactional_fixtures = false fixtures :all setup do @routes = TestApp.routes @@ -167,7 +166,6 @@ class ActiveSupport::TestCase class ActionDispatch::IntegrationTest self.fixture_path = "#{Rails.root}/fixtures" - # self.use_transactional_fixtures = false fixtures :all end From 9469d13a21bdbbb0c128ec2c56cbd79442511199 Mon Sep 17 00:00:00 2001 From: Larry Gebhardt Date: Tue, 17 Mar 2015 15:09:01 -0400 Subject: [PATCH 25/26] Support new `linkage` key for serialized resources --- lib/jsonapi/resource_serializer.rb | 15 +- test/controllers/controller_test.rb | 72 ++--- test/integration/requests/request_test.rb | 26 +- test/unit/serializer/serializer_test.rb | 329 ++++++++++++++-------- 4 files changed, 276 insertions(+), 166 deletions(-) diff --git a/lib/jsonapi/resource_serializer.rb b/lib/jsonapi/resource_serializer.rb index e393de703..dcc451620 100644 --- a/lib/jsonapi/resource_serializer.rb +++ b/lib/jsonapi/resource_serializer.rb @@ -230,9 +230,12 @@ def link_object_has_one(source, association) link_object_hash = {} link_object_hash[:self] = "#{self_href(source)}/links/#{format_route(route)}" link_object_hash[:related] = "#{self_href(source)}/#{format_route(route)}" - # ToDo: Get correct formatting figured out - link_object_hash[:type] = format_route(association.type) - link_object_hash[:id] = foreign_key_value(source, association) + link_object_hash[:linkage] = {} + linkage_id = foreign_key_value(source, association) + if linkage_id + link_object_hash[:linkage][:type] = format_route(association.type) + link_object_hash[:linkage][:id] = linkage_id + end link_object_hash end @@ -243,9 +246,9 @@ def link_object_has_many(source, association, include_linkage) link_object_hash[:self] = "#{self_href(source)}/links/#{format_route(route)}" link_object_hash[:related] = "#{self_href(source)}/#{format_route(route)}" if include_linkage - # ToDo: Get correct formatting figured out - link_object_hash[:type] = format_route(association.type) - link_object_hash[:ids] = foreign_key_value(source, association) + link_object_hash[:linkage] = {} + link_object_hash[:linkage][:type] = format_route(association.type) + link_object_hash[:linkage][:ids] = foreign_key_value(source, association) end link_object_hash end diff --git a/test/controllers/controller_test.rb b/test/controllers/controller_test.rb index a8b6d7f71..ed7806fdb 100644 --- a/test/controllers/controller_test.rb +++ b/test/controllers/controller_test.rb @@ -236,8 +236,8 @@ def test_show_single_with_includes assert json_response['data'].is_a?(Hash) assert_equal 'New post', json_response['data']['title'] assert_equal 'A body!!!', json_response['data']['body'] - assert_nil json_response['data']['links']['tags']['ids'] - assert_equal ['1', '2'], json_response['data']['links']['comments']['ids'] + assert_nil json_response['data']['links']['tags']['linkage'] + assert_equal ['1', '2'], json_response['data']['links']['comments']['linkage']['ids'] assert_equal 2, json_response['included'].size end @@ -247,7 +247,7 @@ def test_show_single_with_fields assert json_response['data'].is_a?(Hash) assert_nil json_response['data']['title'] assert_nil json_response['data']['body'] - assert_equal '1', json_response['data']['links']['author']['id'] + assert_equal '1', json_response['data']['links']['author']['linkage']['id'] end def test_show_single_invalid_id_format @@ -290,7 +290,7 @@ def test_create_simple assert_response :created assert json_response['data'].is_a?(Hash) - assert_equal '3', json_response['data']['links']['author']['id'] + assert_equal '3', json_response['data']['links']['author']['linkage']['id'] assert_equal 'JR is Great', json_response['data']['title'] assert_equal 'JSONAPIResources is the greatest thing since unsliced bread.', json_response['data']['body'] end @@ -385,7 +385,7 @@ def test_create_multiple assert_response :created assert json_response['data'].is_a?(Array) assert_equal json_response['data'].size, 2 - assert_equal json_response['data'][0]['links']['author']['id'], '3' + assert_equal json_response['data'][0]['links']['author']['linkage']['id'], '3' assert_match /JR is Great/, response.body assert_match /Ember is Great/, response.body end @@ -506,7 +506,7 @@ def test_create_with_links_has_many_type_ids assert_response :created assert json_response['data'].is_a?(Hash) - assert_equal '3', json_response['data']['links']['author']['id'] + assert_equal '3', json_response['data']['links']['author']['linkage']['id'] assert_equal 'JR is Great', json_response['data']['title'] assert_equal 'JSONAPIResources is the greatest thing since unsliced bread.', json_response['data']['body'] end @@ -528,7 +528,7 @@ def test_create_with_links_has_many_array assert_response :created assert json_response['data'].is_a?(Hash) - assert_equal '3', json_response['data']['links']['author']['id'] + assert_equal '3', json_response['data']['links']['author']['linkage']['id'] assert_equal 'JR is Great', json_response['data']['title'] assert_equal 'JSONAPIResources is the greatest thing since unsliced bread.', json_response['data']['body'] end @@ -552,7 +552,7 @@ def test_create_with_links_include_and_fields assert_response :created assert json_response['data'].is_a?(Hash) - assert_equal '3', json_response['data']['links']['author']['id'] + assert_equal '3', json_response['data']['links']['author']['linkage']['id'] assert_equal 'JR is Great!', json_response['data']['title'] assert_not_nil json_response['included'].size end @@ -578,11 +578,11 @@ def test_update_with_links assert_response :success assert json_response['data'].is_a?(Hash) - assert_equal '3', json_response['data']['links']['author']['id'] - assert_equal javascript.id.to_s, json_response['data']['links']['section']['id'] + assert_equal '3', json_response['data']['links']['author']['linkage']['id'] + assert_equal javascript.id.to_s, json_response['data']['links']['section']['linkage']['id'] assert_equal 'A great new Post', json_response['data']['title'] assert_equal 'AAAA', json_response['data']['body'] - assert matches_array?(['3', '4'], json_response['data']['links']['tags']['ids']) + assert matches_array?(['3', '4'], json_response['data']['links']['tags']['linkage']['ids']) end def test_update_remove_links @@ -604,11 +604,11 @@ def test_update_remove_links assert_response :success assert json_response['data'].is_a?(Hash) - assert_equal '3', json_response['data']['links']['author']['id'] - assert_equal nil, json_response['data']['links']['section']['id'] + assert_equal '3', json_response['data']['links']['author']['linkage']['id'] + assert_equal nil, json_response['data']['links']['section']['linkage']['id'] assert_equal 'A great new Post', json_response['data']['title'] assert_equal 'AAAA', json_response['data']['body'] - assert matches_array?([], json_response['data']['links']['tags']['ids']) + assert matches_array?([], json_response['data']['links']['tags']['linkage']['ids']) end def test_update_relationship_has_one @@ -1070,17 +1070,17 @@ def test_update_multiple assert_response :success assert_equal json_response['data'].size, 2 - assert_equal json_response['data'][0]['links']['author']['id'], '3' - assert_equal json_response['data'][0]['links']['section']['id'], javascript.id.to_s + assert_equal json_response['data'][0]['links']['author']['linkage']['id'], '3' + assert_equal json_response['data'][0]['links']['section']['linkage']['id'], javascript.id.to_s assert_equal json_response['data'][0]['title'], 'A great new Post QWERTY' assert_equal json_response['data'][0]['body'], 'AAAA' - assert_equal json_response['data'][0]['links']['tags']['ids'], ['3', '4'] + assert_equal json_response['data'][0]['links']['tags']['linkage']['ids'], ['3', '4'] - assert_equal json_response['data'][1]['links']['author']['id'], '3' - assert_equal json_response['data'][1]['links']['section']['id'], javascript.id.to_s + assert_equal json_response['data'][1]['links']['author']['linkage']['id'], '3' + assert_equal json_response['data'][1]['links']['section']['linkage']['id'], javascript.id.to_s assert_equal json_response['data'][1]['title'], 'A great new Post ASDFG' assert_equal json_response['data'][1]['body'], 'Not First!!!!' - assert_equal json_response['data'][1]['links']['tags']['ids'], ['3', '4'] + assert_equal json_response['data'][1]['links']['tags']['linkage']['ids'], ['3', '4'] end def test_update_multiple_missing_keys @@ -1249,11 +1249,13 @@ def test_show_has_one_relationship assert_response :success assert_hash_equals json_response, {data: { + linkage: { type: 'people', - id: '1', - self: 'http://test.host/posts/1/links/author', - related: 'http://test.host/posts/1/author' - } + id: '1' + }, + self: 'http://test.host/posts/1/links/author', + related: 'http://test.host/posts/1/author' + } } end @@ -1262,8 +1264,10 @@ def test_show_has_many_relationship assert_response :success assert_hash_equals json_response, {data: { - type: 'tags', - ids: ['5'], + linkage: { + type: 'tags', + ids: ['5'] + }, self: 'http://test.host/posts/2/links/tags', related: 'http://test.host/posts/2/tags' } @@ -1393,8 +1397,8 @@ def test_create_expense_entries_underscored assert_response :created assert json_response['data'].is_a?(Hash) - assert_equal '3', json_response['data']['links']['employee']['id'] - assert_equal 'USD', json_response['data']['links']['iso_currency']['id'] + assert_equal '3', json_response['data']['links']['employee']['linkage']['id'] + assert_equal 'USD', json_response['data']['links']['iso_currency']['linkage']['id'] assert_equal '50.58', json_response['data']['cost'] delete :destroy, {id: json_response['data']['id']} @@ -1422,8 +1426,8 @@ def test_create_expense_entries_camelized_key assert_response :created assert json_response['data'].is_a?(Hash) - assert_equal '3', json_response['data']['links']['employee']['id'] - assert_equal 'USD', json_response['data']['links']['isoCurrency']['id'] + assert_equal '3', json_response['data']['links']['employee']['linkage']['id'] + assert_equal 'USD', json_response['data']['links']['isoCurrency']['linkage']['id'] assert_equal '50.58', json_response['data']['cost'] delete :destroy, {id: json_response['data']['id']} @@ -1451,8 +1455,8 @@ def test_create_expense_entries_dasherized_key assert_response :created assert json_response['data'].is_a?(Hash) - assert_equal '3', json_response['data']['links']['employee']['id'] - assert_equal 'USD', json_response['data']['links']['iso-currency']['id'] + assert_equal '3', json_response['data']['links']['employee']['linkage']['id'] + assert_equal 'USD', json_response['data']['links']['iso-currency']['linkage']['id'] assert_equal '50.58', json_response['data']['cost'] delete :destroy, {id: json_response['data']['id']} @@ -1741,7 +1745,7 @@ def test_show_post_namespaced def test_show_post_namespaced_include get :show, {id: '1', include: 'writer'} assert_response :success - assert_equal '1', json_response['data']['links']['writer']['id'] + assert_equal '1', json_response['data']['links']['writer']['linkage']['id'] assert_nil json_response['data']['links']['tags'] assert_equal '1', json_response['included'][0]['id'] assert_equal 'writers', json_response['included'][0]['type'] @@ -1777,7 +1781,7 @@ def test_create_simple_namespaced assert_response :created assert json_response['data'].is_a?(Hash) - assert_equal '3', json_response['data']['links']['writer']['id'] + assert_equal '3', json_response['data']['links']['writer']['linkage']['id'] assert_equal 'JR - now with Namespacing', json_response['data']['title'] assert_equal 'JSONAPIResources is the greatest thing since unsliced bread now that it has namespaced resources.', json_response['data']['body'] diff --git a/test/integration/requests/request_test.rb b/test/integration/requests/request_test.rb index 1e1234909..ea2959319 100644 --- a/test/integration/requests/request_test.rb +++ b/test/integration/requests/request_test.rb @@ -69,18 +69,22 @@ def test_get_camelized_route_and_links get '/api/v4/expenseEntries/1/links/isoCurrency' assert_equal 200, status assert_hash_equals({'data' => { - 'type' => 'isoCurrencies', - 'id' => 'USD', - 'self' => 'http://www.example.com/api/v4/expenseEntries/1/links/isoCurrency', - 'related' => 'http://www.example.com/api/v4/expenseEntries/1/isoCurrency'}}, json_response) + 'linkage' => { + 'type' => 'isoCurrencies', + 'id' => 'USD' + }, + 'self' => 'http://www.example.com/api/v4/expenseEntries/1/links/isoCurrency', + 'related' => 'http://www.example.com/api/v4/expenseEntries/1/isoCurrency'}}, json_response) end def test_put_single_without_content_type put '/posts/3', { 'data' => { - 'type' => 'posts', - 'id' => '3', + 'linkage' => { + 'type' => 'posts', + 'id' => '3', + }, 'title' => 'A great new Post', 'links' => { 'tags' => {type: 'tags', ids: [3, 4]} @@ -321,7 +325,10 @@ def test_flow_link_has_many_self_link {'data' => { 'self' => 'http://www.example.com/posts/1/links/tags', 'related' => 'http://www.example.com/posts/1/tags', - 'type' => 'tags', 'ids'=>['1', '2', '3'] + 'linkage' => { + 'type' => 'tags', + 'ids'=>['1', '2', '3'] + } } }) end @@ -343,7 +350,10 @@ def test_flow_link_has_many_self_link_put {'data' => { 'self' => 'http://www.example.com/posts/5/links/tags', 'related' => 'http://www.example.com/posts/5/tags', - 'type' => 'tags', 'ids'=>['10'] + 'linkage' => { + 'type' => 'tags', + 'ids'=>['10'] + } } }) end diff --git a/test/unit/serializer/serializer_test.rb b/test/unit/serializer/serializer_test.rb index 6957fd48b..b8ffd410a 100644 --- a/test/unit/serializer/serializer_test.rb +++ b/test/unit/serializer/serializer_test.rb @@ -31,14 +31,15 @@ def test_serializer section: { self: 'http://example.com/posts/1/links/section', related: 'http://example.com/posts/1/section', - type: 'sections', - id: nil + linkage: { } }, author: { self: 'http://example.com/posts/1/links/author', related: 'http://example.com/posts/1/author', - type: 'people', - id: '1' + linkage: { + type: 'people', + id: '1' + } }, tags: { self: 'http://example.com/posts/1/links/tags', @@ -70,14 +71,16 @@ def test_serializer_namespaced_resource section: { self: 'http://example.com/api/v1/posts/1/links/section', related: 'http://example.com/api/v1/posts/1/section', - type: 'sections', - id: nil + linkage: { + } }, writer: { self: 'http://example.com/api/v1/posts/1/links/writer', related: 'http://example.com/api/v1/posts/1/writer', - type: 'writers', - id: '1' + linkage: { + type: 'writers', + id: '1' + } }, comments: { self: 'http://example.com/api/v1/posts/1/links/comments', @@ -105,8 +108,10 @@ def test_serializer_limited_fieldset author: { self: '/posts/1/links/author', related: '/posts/1/author', - type: 'people', - id: '1' + linkage: { + type: 'people', + id: '1' + } } } } @@ -131,14 +136,16 @@ def test_serializer_include section: { self: '/posts/1/links/section', related: '/posts/1/section', - type: 'sections', - id: nil + linkage: { + } }, author: { self: '/posts/1/links/author', related: '/posts/1/author', - type: 'people', - id: '1' + linkage: { + type: 'people', + id: '1' + } }, tags: { self: '/posts/1/links/tags', @@ -170,8 +177,10 @@ def test_serializer_include preferences: { self: '/people/1/links/preferences', related: '/people/1/preferences', - type: 'preferences', - id: '1' + linkage: { + type: 'preferences', + id: '1' + } } } } @@ -196,14 +205,16 @@ def test_serializer_key_format section: { self: '/posts/1/links/section', related: '/posts/1/section', - type: 'sections', - id: nil + linkage: { + } }, author: { self: '/posts/1/links/author', related: '/posts/1/author', - type: 'people', - id: '1' + linkage: { + type: 'people', + id: '1' + } }, tags: { self: '/posts/1/links/tags', @@ -235,8 +246,10 @@ def test_serializer_key_format preferences: { self: '/people/1/links/preferences', related: '/people/1/preferences', - type: 'preferences', - id: '1' + linkage: { + type: 'preferences', + id: '1' + } } } } @@ -263,14 +276,16 @@ def test_serializer_include_sub_objects section: { self: '/posts/1/links/section', related: '/posts/1/section', - type: 'sections', - id: nil + linkage: { + } }, author: { self: '/posts/1/links/author', related: '/posts/1/author', - type: 'people', - id: '1' + linkage: { + type: 'people', + id: '1' + } }, tags: { self: '/posts/1/links/tags', @@ -279,8 +294,10 @@ def test_serializer_include_sub_objects comments: { self: '/posts/1/links/comments', related: '/posts/1/comments', - type: 'comments', - ids: ['1', '2'] + linkage: { + type: 'comments', + ids: ['1', '2'] + } } } }, @@ -330,20 +347,26 @@ def test_serializer_include_sub_objects author: { self: '/comments/1/links/author', related: '/comments/1/author', - type: 'people', - id: '1' + linkage: { + type: 'people', + id: '1' + } }, post: { self: '/comments/1/links/post', related: '/comments/1/post', - type: 'posts', - id: '1' + linkage: { + type: 'posts', + id: '1' + } }, tags: { self: '/comments/1/links/tags', related: '/comments/1/tags', - type: 'tags', - ids: ['1', '2'] + linkage: { + type: 'tags', + ids: ['1', '2'] + } } } }, @@ -356,20 +379,26 @@ def test_serializer_include_sub_objects author: { self: '/comments/2/links/author', related: '/comments/2/author', - type: 'people', - id: '2' + linkage: { + type: 'people', + id: '2' + } }, post: { self: '/comments/2/links/post', related: '/comments/2/post', - type: 'posts', - id: '1' + linkage: { + type: 'posts', + id: '1' + } }, tags: { self: '/comments/2/links/tags', related: '/comments/2/tags', - type: 'tags', - ids: ['4', '1'] + linkage: { + type: 'tags', + ids: ['4', '1'] + } } } } @@ -395,14 +424,16 @@ def test_serializer_include_has_many_sub_objects_only section: { self: '/posts/1/links/section', related: '/posts/1/section', - type: 'sections', - id: nil + linkage: { + } }, author: { self: '/posts/1/links/author', related: '/posts/1/author', - type: 'people', - id: '1' + linkage: { + type: 'people', + id: '1' + } }, tags: { self: '/posts/1/links/tags', @@ -472,14 +503,16 @@ def test_serializer_include_has_one_sub_objects_only section: { self: '/posts/1/links/section', related: '/posts/1/section', - type: 'sections', - id: nil + linkage: { + } }, author: { self: '/posts/1/links/author', related: '/posts/1/author', - type: 'people', - id: '1' + linkage: { + type: 'people', + id: '1' + } }, tags: { self: '/posts/1/links/tags', @@ -501,14 +534,18 @@ def test_serializer_include_has_one_sub_objects_only author: { self: '/comments/1/links/author', related: '/comments/1/author', - type: 'people', - id: '1' + linkage: { + type: 'people', + id: '1' + } }, post: { self: '/comments/1/links/post', related: '/comments/1/post', - type: 'posts', - id: '1' + linkage: { + type: 'posts', + id: '1' + } }, tags: { self: '/comments/1/links/tags', @@ -542,14 +579,16 @@ def test_serializer_different_foreign_key comments: { self: '/people/2/links/comments', related: '/people/2/comments', - type: 'comments', - ids: ['2', '3'] + linkage: { + type: 'comments', + ids: ['2', '3'] + } }, preferences: { self: "/people/2/links/preferences", related: "/people/2/preferences", - type: "preferences", - id: nil + linkage: { + } } } }, @@ -563,14 +602,18 @@ def test_serializer_different_foreign_key author: { self: '/comments/2/links/author', related: '/comments/2/author', - type: 'people', - id: '2' + linkage: { + type: 'people', + id: '2' + } }, post: { self: '/comments/2/links/post', related: '/comments/2/post', - type: 'posts', - id: '1' + linkage: { + type: 'posts', + id: '1' + } }, tags: { self: '/comments/2/links/tags', @@ -587,14 +630,18 @@ def test_serializer_different_foreign_key author: { self: '/comments/3/links/author', related: '/comments/3/author', - type: 'people', - id: '2' + linkage: { + type: 'people', + id: '2' + } }, post: { self: '/comments/3/links/post', related: '/comments/3/post', - type: 'posts', - id: '2' + linkage: { + type: 'posts', + id: '2' + } }, tags: { self: '/comments/3/links/tags', @@ -629,14 +676,16 @@ def test_serializer_array_of_resources section: { self: '/posts/1/links/section', related: '/posts/1/section', - type: 'sections', - id: nil + linkage: { + } }, author: { self: '/posts/1/links/author', related: '/posts/1/author', - type: 'people', - id: '1' + linkage: { + type: 'people', + id: '1' + } }, tags: { self: '/posts/1/links/tags', @@ -645,8 +694,10 @@ def test_serializer_array_of_resources comments: { self: '/posts/1/links/comments', related: '/posts/1/comments', - type: 'comments', - ids: ['1', '2'] + linkage: { + type: 'comments', + ids: ['1', '2'] + } } } }, @@ -661,14 +712,18 @@ def test_serializer_array_of_resources section: { self: '/posts/2/links/section', related: '/posts/2/section', - type: 'sections', - id: '2' + linkage: { + type: 'sections', + id: '2' + } }, author: { self: '/posts/2/links/author', related: '/posts/2/author', - type: 'people', - id: '1' + linkage: { + type: 'people', + id: '1' + } }, tags: { self: '/posts/2/links/tags', @@ -677,8 +732,10 @@ def test_serializer_array_of_resources comments: { self: '/posts/2/links/comments', related: '/posts/2/comments', - type: 'comments', - ids: ['3'] + linkage: { + type: 'comments', + ids: ['3'] + } } } } @@ -741,20 +798,26 @@ def test_serializer_array_of_resources author: { self: '/comments/1/links/author', related: '/comments/1/author', - type: 'people', - id: '1' + linkage: { + type: 'people', + id: '1' + } }, post: { self: '/comments/1/links/post', related: '/comments/1/post', - type: 'posts', - id: '1' + linkage: { + type: 'posts', + id: '1' + } }, tags: { self: '/comments/1/links/tags', related: '/comments/1/tags', - type: 'tags', - ids: ['1', '2'] + linkage: { + type: 'tags', + ids: ['1', '2'] + } } } }, @@ -767,20 +830,26 @@ def test_serializer_array_of_resources author: { self: '/comments/2/links/author', related: '/comments/2/author', - type: 'people', - id: '2' + linkage: { + type: 'people', + id: '2' + } }, post: { self: '/comments/2/links/post', related: '/comments/2/post', - type: 'posts', - id: '1' + linkage: { + type: 'posts', + id: '1' + } }, tags: { self: '/comments/2/links/tags', related: '/comments/2/tags', - type: 'tags', - ids: ['4', '1'] + linkage: { + type: 'tags', + ids: ['4', '1'] + } } } }, @@ -793,20 +862,26 @@ def test_serializer_array_of_resources author: { self: '/comments/3/links/author', related: '/comments/3/author', - type: 'people', - id: '2' + linkage: { + type: 'people', + id: '2' + } }, post: { self: '/comments/3/links/post', related: '/comments/3/post', - type: 'posts', - id: '2' + linkage: { + type: 'posts', + id: '2' + } }, tags: { self: '/comments/3/links/tags', related: '/comments/3/tags', - type: 'tags', - ids: ['5'] + linkage: { + type: 'tags', + ids: ['5'] + } } } } @@ -836,8 +911,10 @@ def test_serializer_array_of_resources_limited_fields author: { self: '/posts/1/links/author', related: '/posts/1/author', - type: 'people', - id: '1' + linkage: { + type: 'people', + id: '1' + } } } }, @@ -850,8 +927,10 @@ def test_serializer_array_of_resources_limited_fields author: { self: '/posts/2/links/author', related: '/posts/2/author', - type: 'people', - id: '1' + linkage: { + type: 'people', + id: '1' + } } } } @@ -866,8 +945,10 @@ def test_serializer_array_of_resources_limited_fields author: { self: '/posts/11/links/author', related: '/posts/11/author', - type: 'people', - id: '1' + linkage: { + type: 'people', + id: '1' + } } } }, @@ -924,8 +1005,10 @@ def test_serializer_array_of_resources_limited_fields post: { self: '/comments/1/links/post', related: '/comments/1/post', - type: 'posts', - id: '1' + linkage: { + type: 'posts', + id: '1' + } } } }, @@ -938,8 +1021,10 @@ def test_serializer_array_of_resources_limited_fields post: { self: '/comments/2/links/post', related: '/comments/2/post', - type: 'posts', - id: '1' + linkage: { + type: 'posts', + id: '1' + } } } }, @@ -952,8 +1037,10 @@ def test_serializer_array_of_resources_limited_fields post: { self: '/comments/3/links/post', related: '/comments/3/post', - type: 'posts', - id: '2' + linkage: { + type: 'posts', + id: '2' + } } } } @@ -983,14 +1070,18 @@ def test_serializer_camelized_with_value_formatters isoCurrency: { self: '/expense_entries/1/links/iso_currency', related: '/expense_entries/1/iso_currency', - type: 'iso_currencies', - id: 'USD' + linkage: { + type: 'iso_currencies', + id: 'USD' + } }, employee: { self: '/expense_entries/1/links/employee', related: '/expense_entries/1/employee', - type: 'people', - id: '3' + linkage: { + type: 'people', + id: '3' + } } } }, @@ -1040,8 +1131,8 @@ def test_serializer_empty_links_null_and_array planetType: { self: '/planets/8/links/planet_type', related: '/planets/8/planet_type', - type: 'planet_types', - id: nil + linkage: { + } }, tags: { self: '/planets/8/links/tags', @@ -1078,8 +1169,10 @@ def test_serializer_include_with_empty_links_null_and_array planetType: { self: '/planets/7/links/planet_type', related: '/planets/7/planet_type', - type: 'planet_types', - id: '5' + linkage: { + type: 'planet_types', + id: '5' + } }, tags: { self: '/planets/7/links/tags', @@ -1101,8 +1194,8 @@ def test_serializer_include_with_empty_links_null_and_array planetType: { self: '/planets/8/links/planet_type', related: '/planets/8/planet_type', - type: 'planet_types', - id: nil + linkage: { + } }, tags: { self: '/planets/8/links/tags', @@ -1144,8 +1237,8 @@ def test_serializer_booleans author: { self: '/preferences/1/links/author', related: '/preferences/1/author', - type: 'people', - id: nil + linkage: { + } }, friends: { self: '/preferences/1/links/friends', From 2ed04988eea53d9d348d53f6a20b519c4f0d68c7 Mon Sep 17 00:00:00 2001 From: Larry Gebhardt Date: Wed, 18 Mar 2015 14:27:20 -0400 Subject: [PATCH 26/26] Support new linkage format --- lib/jsonapi/exceptions.rb | 7 +- lib/jsonapi/request.rb | 20 +--- lib/jsonapi/resource_serializer.rb | 62 +++++++--- test/controllers/controller_test.rb | 135 +++++++++++----------- test/integration/requests/request_test.rb | 83 ++++++++----- test/unit/serializer/serializer_test.rb | 70 ++++++----- 6 files changed, 208 insertions(+), 169 deletions(-) diff --git a/lib/jsonapi/exceptions.rb b/lib/jsonapi/exceptions.rb index 5282c3eea..d1d9c9697 100644 --- a/lib/jsonapi/exceptions.rb +++ b/lib/jsonapi/exceptions.rb @@ -103,16 +103,11 @@ def errors end class InvalidLinksObject < Error - attr_accessor :value - def initialize(value) - @value = value - end - def errors [JSONAPI::Error.new(code: JSONAPI::INVALID_LINKS_OBJECT, status: :bad_request, title: 'Invalid Links Object', - detail: "#{value} is not a valid Links Object.")] + detail: 'Data is not a valid Links Object.')] end end diff --git a/lib/jsonapi/request.rb b/lib/jsonapi/request.rb index 10ba3c0bc..ff37dcd5a 100644 --- a/lib/jsonapi/request.rb +++ b/lib/jsonapi/request.rb @@ -232,7 +232,7 @@ def parse_has_one_links_object(raw) end if !raw.is_a?(Hash) || raw.length != 2 || !(raw.has_key?('type') && raw.has_key?('id')) - raise JSONAPI::Exceptions::InvalidLinksObject.new(raw) + raise JSONAPI::Exceptions::InvalidLinksObject.new end { @@ -243,23 +243,18 @@ def parse_has_one_links_object(raw) def parse_has_many_links_object(raw) if raw.nil? - raise JSONAPI::Exceptions::InvalidLinksObject.new(raw) + raise JSONAPI::Exceptions::InvalidLinksObject.new end links_object = {} - if raw.is_a?(Hash) - if raw.length != 2 || !(raw.has_key?('type') && raw.has_key?('ids')) || !(raw['ids'].is_a?(Array)) - raise JSONAPI::Exceptions::InvalidLinksObject.new(raw) - end - links_object[raw['type']] = raw['ids'] - elsif raw.is_a?(Array) + if raw.is_a?(Array) raw.each do |link| link_object = parse_has_one_links_object(link) links_object[link_object[:type]] ||= [] links_object[link_object[:type]].push(link_object[:id]) end else - raise JSONAPI::Exceptions::InvalidLinksObject.new(raw) + raise JSONAPI::Exceptions::InvalidLinksObject.new end links_object end @@ -351,10 +346,7 @@ def parse_add_association_operation(data, association_type, parent_key) association = resource_klass._association(association_type) if association.is_a?(JSONAPI::Association::HasMany) - ids = data.require(:ids) - type = data.require(:type) - - object_params = {links: {association.name => {'type' => type, 'ids' => ids}}} + object_params = {links: {association.name => data}} verified_param_set = parse_params(object_params, @resource_klass.updateable_fields(@context)) @operations.push JSONAPI::CreateHasManyAssociationOperation.new(resource_klass, @@ -362,8 +354,6 @@ def parse_add_association_operation(data, association_type, parent_key) association_type, verified_param_set[:has_many].values[0]) end - rescue ActionController::ParameterMissing => e - @errors.concat(JSONAPI::Exceptions::ParameterMissing.new(e.param).errors) end def parse_update_association_operation(data, association_type, parent_key) diff --git a/lib/jsonapi/resource_serializer.rb b/lib/jsonapi/resource_serializer.rb index dcc451620..6ff35e71c 100644 --- a/lib/jsonapi/resource_serializer.rb +++ b/lib/jsonapi/resource_serializer.rb @@ -56,7 +56,19 @@ def serialize_to_hash(source) end def serialize_to_links_hash(source, requested_association) - {data: link_object(source, requested_association, true)} + if requested_association.is_a?(JSONAPI::Association::HasOne) + data = has_one_linkage(source, requested_association) + else + data = has_many_linkage(source, requested_association) + end + + { + links: { + self: self_link(source, requested_association), + related: related_link(source, requested_association) + }, + data: data + } end private @@ -224,32 +236,46 @@ def format_route(route) @route_formatter.format(route.to_s) end - def link_object_has_one(source, association) - route = association.name + def self_link(source, association) + "#{self_href(source)}/links/#{format_route(association.name)}" + end - link_object_hash = {} - link_object_hash[:self] = "#{self_href(source)}/links/#{format_route(route)}" - link_object_hash[:related] = "#{self_href(source)}/#{format_route(route)}" - link_object_hash[:linkage] = {} + def related_link(source, association) + "#{self_href(source)}/#{format_route(association.name)}" + end + + def has_one_linkage(source, association) + linkage = {} linkage_id = foreign_key_value(source, association) if linkage_id - link_object_hash[:linkage][:type] = format_route(association.type) - link_object_hash[:linkage][:id] = linkage_id + linkage[:type] = format_route(association.type) + linkage[:id] = linkage_id end + linkage + end + + def has_many_linkage(source, association) + linkage = [] + linkage_ids = foreign_key_value(source, association) + linkage_ids.each do |linkage_id| + linkage.append({type: format_route(association.type), id: linkage_id}) + end + linkage + end + + def link_object_has_one(source, association) + link_object_hash = {} + link_object_hash[:self] = self_link(source, association) + link_object_hash[:related] = related_link(source, association) + link_object_hash[:linkage] = has_one_linkage(source, association) link_object_hash end def link_object_has_many(source, association, include_linkage) - route = association.name - link_object_hash = {} - link_object_hash[:self] = "#{self_href(source)}/links/#{format_route(route)}" - link_object_hash[:related] = "#{self_href(source)}/#{format_route(route)}" - if include_linkage - link_object_hash[:linkage] = {} - link_object_hash[:linkage][:type] = format_route(association.type) - link_object_hash[:linkage][:ids] = foreign_key_value(source, association) - end + link_object_hash[:self] = self_link(source, association) + link_object_hash[:related] = related_link(source, association) + link_object_hash[:linkage] = has_many_linkage(source, association) if include_linkage link_object_hash end diff --git a/test/controllers/controller_test.rb b/test/controllers/controller_test.rb index ed7806fdb..b66f40a14 100644 --- a/test/controllers/controller_test.rb +++ b/test/controllers/controller_test.rb @@ -215,12 +215,6 @@ def test_excluded_sort_param assert_match /id is not a valid sort criteria for post/, response.body end - # ToDo: test validating the parameter values - # def test_index_invalid_filter_value - # get :index, {ids: [1,'asdfg1']} - # assert_response :bad_request - # end - def test_show_single get :show, {id: '1'} assert_response :success @@ -237,7 +231,8 @@ def test_show_single_with_includes assert_equal 'New post', json_response['data']['title'] assert_equal 'A body!!!', json_response['data']['body'] assert_nil json_response['data']['links']['tags']['linkage'] - assert_equal ['1', '2'], json_response['data']['links']['comments']['linkage']['ids'] + assert matches_array?([{'type' => 'comments', 'id' => '1'}, {'type' => 'comments', 'id' => '2'}], + json_response['data']['links']['comments']['linkage']) assert_equal 2, json_response['included'].size end @@ -499,7 +494,7 @@ def test_create_with_links_has_many_type_ids body: 'JSONAPIResources is the greatest thing since unsliced bread.', links: { author: {type: 'people', id: '3'}, - tags: {type: 'tags', ids: [3, 4]} + tags: [{type: 'tags', id: 3}, {type: 'tags', id: 4}] } } } @@ -543,7 +538,7 @@ def test_create_with_links_include_and_fields body: 'JSONAPIResources is the greatest thing since unsliced bread!', links: { author: {type: 'people', id: '3'}, - tags: {type: 'tags', ids: [3, 4]} + tags: [{type: 'tags', id: 3}, {type: 'tags', id: 4}] } }, include: 'author,author.posts', @@ -570,7 +565,7 @@ def test_update_with_links title: 'A great new Post', links: { section: {type: 'sections', id: "#{javascript.id}"}, - tags: {type: 'tags', ids: [3, 4]} + tags: [{type: 'tags', id: 3}, {type: 'tags', id: 4}] } }, include: 'tags' @@ -582,7 +577,8 @@ def test_update_with_links assert_equal javascript.id.to_s, json_response['data']['links']['section']['linkage']['id'] assert_equal 'A great new Post', json_response['data']['title'] assert_equal 'AAAA', json_response['data']['body'] - assert matches_array?(['3', '4'], json_response['data']['links']['tags']['linkage']['ids']) + assert matches_array?([{'type' => 'tags', 'id' => '3'}, {'type' => 'tags', 'id' => '4'}], + json_response['data']['links']['tags']['linkage']) end def test_update_remove_links @@ -608,7 +604,8 @@ def test_update_remove_links assert_equal nil, json_response['data']['links']['section']['linkage']['id'] assert_equal 'A great new Post', json_response['data']['title'] assert_equal 'AAAA', json_response['data']['body'] - assert matches_array?([], json_response['data']['links']['tags']['linkage']['ids']) + assert matches_array?([], + json_response['data']['links']['tags']['linkage']) end def test_update_relationship_has_one @@ -640,6 +637,14 @@ def test_update_relationship_has_one_invalid_links_hash_count assert_match /Invalid Links Object/, response.body end + def test_update_relationship_has_many_not_array + set_content_type_header! + put :update_association, {post_id: 3, association: 'tags', data: {type: 'tags', id: 2}} + + assert_response :bad_request + assert_match /Invalid Links Object/, response.body + end + def test_update_relationship_has_one_invalid_links_hash_keys_type_mismatch set_content_type_header! put :update_association, {post_id: 3, association: 'section', data: {type: 'comment', id: '3'}} @@ -758,19 +763,19 @@ def test_update_relationship_has_one_singular_param def test_update_relationship_has_many_join_table_single set_content_type_header! - put :update_association, {post_id: 3, association: 'tags', data: {type: 'tags', ids: []}} + put :update_association, {post_id: 3, association: 'tags', data: []} assert_response :no_content post_object = Post.find(3) assert_equal 0, post_object.tags.length - put :update_association, {post_id: 3, association: 'tags', data: {type: 'tags', ids: [2]}} + put :update_association, {post_id: 3, association: 'tags', data: [{type: 'tags', id: 2}]} assert_response :no_content post_object = Post.find(3) assert_equal 1, post_object.tags.length - put :update_association, {post_id: 3, association: 'tags', data: {type: 'tags', ids: [5]}} + put :update_association, {post_id: 3, association: 'tags', data: [{type: 'tags', id: 5}]} assert_response :no_content post_object = Post.find(3) @@ -779,17 +784,7 @@ def test_update_relationship_has_many_join_table_single assert matches_array? [5], tags end - def test_update_relationship_has_many_join_table_homogenous - set_content_type_header! - put :update_association, {post_id: 3, association: 'tags', data: {type: 'tags', ids: [2, 3]}} - - assert_response :no_content - post_object = Post.find(3) - assert_equal 2, post_object.tags.collect { |tag| tag.id }.length - assert matches_array? [2, 3], post_object.tags.collect { |tag| tag.id } - end - - def test_update_relationship_has_many_join_table_heterogenous + def test_update_relationship_has_many set_content_type_header! put :update_association, {post_id: 3, association: 'tags', data: [{type: 'tags', id: 2}, {type: 'tags', id: 3}]} @@ -801,14 +796,14 @@ def test_update_relationship_has_many_join_table_heterogenous def test_create_relationship_has_many_join_table set_content_type_header! - put :update_association, {post_id: 3, association: 'tags', data: {type: 'tags', ids: [2, 3]}} + put :update_association, {post_id: 3, association: 'tags', data: [{type: 'tags', id: 2}, {type: 'tags', id: 3}]} assert_response :no_content post_object = Post.find(3) assert_equal 2, post_object.tags.collect { |tag| tag.id }.length assert matches_array? [2, 3], post_object.tags.collect { |tag| tag.id } - post :create_association, {post_id: 3, association: 'tags', data: {type: 'tags', ids: [5]}} + post :create_association, {post_id: 3, association: 'tags', data: [{type: 'tags', id: 5}]} assert_response :no_content post_object = Post.find(3) @@ -818,7 +813,7 @@ def test_create_relationship_has_many_join_table def test_create_relationship_has_many_mismatched_type set_content_type_header! - post :create_association, {post_id: 3, association: 'tags', data: {type: 'comments', ids: [5]}} + post :create_association, {post_id: 3, association: 'tags', data: [{type: 'comments', id: 5}]} assert_response :bad_request assert_match /Type Mismatch/, response.body @@ -826,10 +821,18 @@ def test_create_relationship_has_many_mismatched_type def test_create_relationship_has_many_missing_id set_content_type_header! - post :create_association, {post_id: 3, association: 'tags', data: {type: 'tags', idds: [5]}} + post :create_association, {post_id: 3, association: 'tags', data: [{type: 'tags', idd: 5}]} assert_response :bad_request - assert_match /The required parameter, ids, is missing/, response.body + assert_match /Data is not a valid Links Object./, response.body + end + + def test_create_relationship_has_many_not_array + set_content_type_header! + post :create_association, {post_id: 3, association: 'tags', data: {type: 'tags', id: 5}} + + assert_response :bad_request + assert_match /Data is not a valid Links Object./, response.body end def test_create_relationship_has_many_missing_data @@ -842,20 +845,20 @@ def test_create_relationship_has_many_missing_data def test_create_relationship_has_many_join set_content_type_header! - post :create_association, {post_id: 4, association: 'tags', data: {type: 'tags', ids: [1, 2, 3]}} + post :create_association, {post_id: 4, association: 'tags', data: [{type: 'tags', id: 1}, {type: 'tags', id: 2}, {type: 'tags', id: 3}]} assert_response :no_content end def test_create_relationship_has_many_join_table_record_exists set_content_type_header! - put :update_association, {post_id: 3, association: 'tags', data: {type: 'tags', ids: [2, 3]}} + put :update_association, {post_id: 3, association: 'tags', data: [{type: 'tags', id: 2}, {type: 'tags', id: 3}]} assert_response :no_content post_object = Post.find(3) assert_equal 2, post_object.tags.collect { |tag| tag.id }.length assert matches_array? [2, 3], post_object.tags.collect { |tag| tag.id } - post :create_association, {post_id: 3, association: 'tags', data: {type: 'tags', ids: [5, 2]}} + post :create_association, {post_id: 3, association: 'tags', data: [{type: 'tags', id: 2}, {type: 'tags', id: 5}]} assert_response :bad_request assert_match /The relation to 2 already exists./, response.body @@ -871,7 +874,7 @@ def test_update_relationship_has_many_missing_tags def test_delete_relationship_has_many set_content_type_header! - put :update_association, {post_id: 14, association: 'tags', data: {type: 'tags', ids: [2, 3]}} + put :update_association, {post_id: 14, association: 'tags', data: [{type: 'tags', id: 2}, {type: 'tags', id: 3}]} assert_response :no_content p = Post.find(14) assert_equal [2, 3], p.tag_ids @@ -885,7 +888,7 @@ def test_delete_relationship_has_many def test_delete_relationship_has_many_does_not_exist set_content_type_header! - put :update_association, {post_id: 14, association: 'tags', data: {type: 'tags', ids: [2, 3]}} + put :update_association, {post_id: 14, association: 'tags', data: [{type: 'tags', id: 2}, {type: 'tags', id: 3}]} assert_response :no_content p = Post.find(14) assert_equal [2, 3], p.tag_ids @@ -899,7 +902,7 @@ def test_delete_relationship_has_many_does_not_exist def test_delete_relationship_has_many_with_empty_data set_content_type_header! - put :update_association, {post_id: 14, association: 'tags', data: {type: 'tags', ids: [2, 3]}} + put :update_association, {post_id: 14, association: 'tags', data: [{type: 'tags', id: 2}, {type: 'tags', id: 3}]} assert_response :no_content p = Post.find(14) assert_equal [2, 3], p.tag_ids @@ -924,7 +927,7 @@ def test_update_mismatched_keys title: 'A great new Post', links: { section: {type: 'sections', id: "#{javascript.id}"}, - tags: {type: 'tags', ids: [3, 4]} + tags: [{type: 'tags', id: 3}, {type: 'tags', id: 4}] } } } @@ -947,7 +950,7 @@ def test_update_extra_param title: 'A great new Post', links: { section: {type: 'sections', id: "#{javascript.id}"}, - tags: {type: 'tags', ids: [3, 4]} + tags: [{type: 'tags', id: 3}, {type: 'tags', id: 4}] } } } @@ -970,7 +973,7 @@ def test_update_extra_param_in_links links: { asdfg: 'aaaa', section: {type: 'sections', id: "#{javascript.id}"}, - tags: {type: 'tags', ids: [3, 4]} + tags: [{type: 'tags', id: 3}, {type: 'tags', id: 4}] } } } @@ -991,7 +994,7 @@ def test_update_missing_param title: 'A great new Post', links: { section: {type: 'sections', id: "#{javascript.id}"}, - tags: {type: 'tags', ids: [3, 4]} + tags: [{type: 'tags', id: 3}, {type: 'tags', id: 4}] } } } @@ -1029,7 +1032,7 @@ def test_update_missing_type title: 'A great new Post', links: { section: {type: 'sections', id: "#{javascript.id}"}, - tags: {type: 'tags', ids: [3, 4]} + tags: [{type: 'tags', id: 3}, {type: 'tags', id: 4}] } } } @@ -1052,7 +1055,7 @@ def test_update_multiple title: 'A great new Post QWERTY', links: { section: {type: 'sections', id: "#{javascript.id}"}, - tags: {type: 'tags', ids: [3, 4]} + tags: [{type: 'tags', id: 3}, {type: 'tags', id: 4}] } }, { @@ -1061,7 +1064,7 @@ def test_update_multiple title: 'A great new Post ASDFG', links: { section: {type: 'sections', id: "#{javascript.id}"}, - tags: {type: 'tags', ids: [3, 4]} + tags: [{type: 'tags', id: 3}, {type: 'tags', id: 4}] } } ], @@ -1074,13 +1077,15 @@ def test_update_multiple assert_equal json_response['data'][0]['links']['section']['linkage']['id'], javascript.id.to_s assert_equal json_response['data'][0]['title'], 'A great new Post QWERTY' assert_equal json_response['data'][0]['body'], 'AAAA' - assert_equal json_response['data'][0]['links']['tags']['linkage']['ids'], ['3', '4'] + assert matches_array?([{'type' => 'tags', 'id' => '3'}, {'type' => 'tags', 'id' => '4'}], + json_response['data'][0]['links']['tags']['linkage']) assert_equal json_response['data'][1]['links']['author']['linkage']['id'], '3' assert_equal json_response['data'][1]['links']['section']['linkage']['id'], javascript.id.to_s assert_equal json_response['data'][1]['title'], 'A great new Post ASDFG' assert_equal json_response['data'][1]['body'], 'Not First!!!!' - assert_equal json_response['data'][1]['links']['tags']['linkage']['ids'], ['3', '4'] + assert matches_array?([{'type' => 'tags', 'id' => '3'}, {'type' => 'tags', 'id' => '4'}], + json_response['data'][1]['links']['tags']['linkage']) end def test_update_multiple_missing_keys @@ -1096,7 +1101,7 @@ def test_update_multiple_missing_keys title: 'A great new Post ASDFG', links: { section: {type: 'sections', id: "#{javascript.id}"}, - tags: {type: 'tags', ids: [3, 4]} + tags: [{type: 'tags', id: 3}, {type: 'tags', id: 4}] } }, { @@ -1104,7 +1109,7 @@ def test_update_multiple_missing_keys title: 'A great new Post QWERTY', links: { section: {type: 'sections', id: "#{javascript.id}"}, - tags: {type: 'tags', ids: [3, 4]} + tags: [{type: 'tags', id: 3}, {type: 'tags', id: 4}] } } ]} @@ -1127,7 +1132,7 @@ def test_update_mismatch_keys title: 'A great new Post ASDFG', links: { section: {type: 'sections', id: "#{javascript.id}"}, - tags: {type: 'tags', ids: [3, 4]} + tags: [{type: 'tags', id: 3}, {type: 'tags', id: 4}] } }, { @@ -1136,7 +1141,7 @@ def test_update_mismatch_keys title: 'A great new Post QWERTY', links: { section: {type: 'sections', id: "#{javascript.id}"}, - tags: {type: 'tags', ids: [3, 4]} + tags: [{type: 'tags', id: 3}, {type: 'tags', id: 4}] } } ]} @@ -1159,7 +1164,7 @@ def test_update_multiple_count_mismatch title: 'A great new Post QWERTY', links: { section: {type: 'sections', id: "#{javascript.id}"}, - tags: {type: 'tags', ids: [3, 4]} + tags: [{type: 'tags', id: 3}, {type: 'tags', id: 4}] } }, { @@ -1168,7 +1173,7 @@ def test_update_multiple_count_mismatch title: 'A great new Post ASDFG', links: { section: {type: 'sections', id: "#{javascript.id}"}, - tags: {type: 'tags', ids: [3, 4]} + tags: [{type: 'tags', id: 3}, {type: 'tags', id: 4}] } } ]} @@ -1188,7 +1193,7 @@ def test_update_unpermitted_attributes subject: 'A great new Post', links: { author: {type: 'people', id: '1'}, - tags: {type: 'tags', ids: [3, 4]} + tags: [{type: 'tags', id: 3}, {type: 'tags', id: 4}] } } } @@ -1208,7 +1213,7 @@ def test_update_bad_attributes subject: 'A great new Post', linked_objects: { author: {type: 'people', id: '1'}, - tags: {type: 'tags', ids: [3, 4]} + tags: [{type: 'tags', id: 3}, {type: 'tags', id: 4}] } } } @@ -1249,12 +1254,12 @@ def test_show_has_one_relationship assert_response :success assert_hash_equals json_response, {data: { - linkage: { - type: 'people', - id: '1' - }, - self: 'http://test.host/posts/1/links/author', - related: 'http://test.host/posts/1/author' + type: 'people', + id: '1' + }, + links: { + self: 'http://test.host/posts/1/links/author', + related: 'http://test.host/posts/1/author' } } end @@ -1263,11 +1268,11 @@ def test_show_has_many_relationship get :show_association, {post_id: '2', association: 'tags'} assert_response :success assert_hash_equals json_response, - {data: { - linkage: { - type: 'tags', - ids: ['5'] - }, + { + data: [ + {type: 'tags', id: '5'} + ], + links: { self: 'http://test.host/posts/2/links/tags', related: 'http://test.host/posts/2/tags' } diff --git a/test/integration/requests/request_test.rb b/test/integration/requests/request_test.rb index ea2959319..fcf693d96 100644 --- a/test/integration/requests/request_test.rb +++ b/test/integration/requests/request_test.rb @@ -68,13 +68,15 @@ def test_get_camelized_route_and_links JSONAPI.configuration.route_format = :camelized_route get '/api/v4/expenseEntries/1/links/isoCurrency' assert_equal 200, status - assert_hash_equals({'data' => { - 'linkage' => { - 'type' => 'isoCurrencies', - 'id' => 'USD' - }, + assert_hash_equals({'links' => { 'self' => 'http://www.example.com/api/v4/expenseEntries/1/links/isoCurrency', - 'related' => 'http://www.example.com/api/v4/expenseEntries/1/isoCurrency'}}, json_response) + 'related' => 'http://www.example.com/api/v4/expenseEntries/1/isoCurrency' + }, + 'data' => { + 'type' => 'isoCurrencies', + 'id' => 'USD' + } + }, json_response) end def test_put_single_without_content_type @@ -87,7 +89,10 @@ def test_put_single_without_content_type }, 'title' => 'A great new Post', 'links' => { - 'tags' => {type: 'tags', ids: [3, 4]} + 'tags' => [ + {type: 'tags', id: 3}, + {type: 'tags', id: 4} + ] } } }.to_json, "CONTENT_TYPE" => "application/json" @@ -103,7 +108,10 @@ def test_put_single 'id' => '3', 'title' => 'A great new Post', 'links' => { - 'tags' => {type: 'tags', ids: [3, 4]} + 'tags' => [ + {type: 'tags', id: 3}, + {type: 'tags', id: 4} + ] } } }.to_json, "CONTENT_TYPE" => JSONAPI::MEDIA_TYPE @@ -117,7 +125,10 @@ def test_post_single_without_content_type 'posts' => { 'title' => 'A great new Post', 'links' => { - 'tags' => [3, 4] + 'tags' => [ + {type: 'tags', id: 3}, + {type: 'tags', id: 4} + ] } } }.to_json, "CONTENT_TYPE" => "application/json" @@ -180,7 +191,10 @@ def test_put_content_type 'id' => '3', 'title' => 'A great new Post', 'links' => { - 'tags' => {type: 'tags', ids: [3, 4]} + 'tags' => [ + {type: 'tags', id: 3}, + {type: 'tags', id: 4} + ] } } }.to_json, "CONTENT_TYPE" => JSONAPI::MEDIA_TYPE @@ -196,7 +210,10 @@ def test_patch_content_type 'id' => '3', 'title' => 'A great new Post', 'links' => { - 'tags' => {type: 'tags', ids: [3, 4]} + 'tags' => [ + {type: 'tags', id: 3}, + {type: 'tags', id: 4} + ] } } }.to_json, "CONTENT_TYPE" => JSONAPI::MEDIA_TYPE @@ -311,7 +328,13 @@ def test_flow_link_has_one_self_link get post_1['links']['author']['self'] assert_equal 200, status - assert_hash_equals(json_response, {'data' => post_1['links']['author']}) + assert_hash_equals(json_response, { + 'links' => { + 'self' => 'http://www.example.com/posts/1/links/author', + 'related' => 'http://www.example.com/posts/1/author' + }, + 'data' => {type: 'people', id: '1'} + }) end def test_flow_link_has_many_self_link @@ -322,14 +345,16 @@ def test_flow_link_has_many_self_link get post_1['links']['tags']['self'] assert_equal 200, status assert_hash_equals(json_response, - {'data' => { - 'self' => 'http://www.example.com/posts/1/links/tags', - 'related' => 'http://www.example.com/posts/1/tags', - 'linkage' => { - 'type' => 'tags', - 'ids'=>['1', '2', '3'] - } - } + { + 'links' => { + 'self' => 'http://www.example.com/posts/1/links/tags', + 'related' => 'http://www.example.com/posts/1/tags' + }, + 'data' => [ + {type: 'tags', id: '1'}, + {type: 'tags', id: '2'}, + {type: 'tags', id: '3'} + ] }) end @@ -339,7 +364,7 @@ def test_flow_link_has_many_self_link_put post_1 = json_response['data'][4] post post_1['links']['tags']['self'], - {'data' => {'type' => 'tags', 'ids' => ['10']}}.to_json, + {'data' => [{'type' => 'tags', 'id' => '10'}]}.to_json, "CONTENT_TYPE" => JSONAPI::MEDIA_TYPE assert_equal 204, status @@ -347,14 +372,14 @@ def test_flow_link_has_many_self_link_put get post_1['links']['tags']['self'] assert_equal 200, status assert_hash_equals(json_response, - {'data' => { - 'self' => 'http://www.example.com/posts/5/links/tags', - 'related' => 'http://www.example.com/posts/5/tags', - 'linkage' => { - 'type' => 'tags', - 'ids'=>['10'] - } - } + { + 'links' => { + 'self' => 'http://www.example.com/posts/5/links/tags', + 'related' => 'http://www.example.com/posts/5/tags' + }, + 'data' => [ + {type: 'tags', id: '10'} + ] }) end diff --git a/test/unit/serializer/serializer_test.rb b/test/unit/serializer/serializer_test.rb index b8ffd410a..9f7206732 100644 --- a/test/unit/serializer/serializer_test.rb +++ b/test/unit/serializer/serializer_test.rb @@ -294,10 +294,10 @@ def test_serializer_include_sub_objects comments: { self: '/posts/1/links/comments', related: '/posts/1/comments', - linkage: { - type: 'comments', - ids: ['1', '2'] - } + linkage: [ + {type: 'comments', id: '1'}, + {type: 'comments', id: '2'} + ] } } }, @@ -363,10 +363,10 @@ def test_serializer_include_sub_objects tags: { self: '/comments/1/links/tags', related: '/comments/1/tags', - linkage: { - type: 'tags', - ids: ['1', '2'] - } + linkage: [ + {type: 'tags', id: '1'}, + {type: 'tags', id: '2'} + ] } } }, @@ -395,10 +395,10 @@ def test_serializer_include_sub_objects tags: { self: '/comments/2/links/tags', related: '/comments/2/tags', - linkage: { - type: 'tags', - ids: ['4', '1'] - } + linkage: [ + {type: 'tags', id: '1'}, + {type: 'tags', id: '4'} + ] } } } @@ -579,10 +579,10 @@ def test_serializer_different_foreign_key comments: { self: '/people/2/links/comments', related: '/people/2/comments', - linkage: { - type: 'comments', - ids: ['2', '3'] - } + linkage: [ + {type: 'comments', id: '2'}, + {type: 'comments', id: '3'} + ] }, preferences: { self: "/people/2/links/preferences", @@ -694,10 +694,10 @@ def test_serializer_array_of_resources comments: { self: '/posts/1/links/comments', related: '/posts/1/comments', - linkage: { - type: 'comments', - ids: ['1', '2'] - } + linkage: [ + {type: 'comments', id: '1'}, + {type: 'comments', id: '2'} + ] } } }, @@ -732,10 +732,9 @@ def test_serializer_array_of_resources comments: { self: '/posts/2/links/comments', related: '/posts/2/comments', - linkage: { - type: 'comments', - ids: ['3'] - } + linkage: [ + {type: 'comments', id: '3'} + ] } } } @@ -814,10 +813,10 @@ def test_serializer_array_of_resources tags: { self: '/comments/1/links/tags', related: '/comments/1/tags', - linkage: { - type: 'tags', - ids: ['1', '2'] - } + linkage: [ + {type: 'tags', id: '1'}, + {type: 'tags', id: '2'} + ] } } }, @@ -846,10 +845,10 @@ def test_serializer_array_of_resources tags: { self: '/comments/2/links/tags', related: '/comments/2/tags', - linkage: { - type: 'tags', - ids: ['4', '1'] - } + linkage: [ + {type: 'tags', id: '4'}, + {type: 'tags', id: '1'} + ] } } }, @@ -878,10 +877,9 @@ def test_serializer_array_of_resources tags: { self: '/comments/3/links/tags', related: '/comments/3/tags', - linkage: { - type: 'tags', - ids: ['5'] - } + linkage: [ + {type: 'tags', id: '5'} + ] } } }