Skip to content

Commit

Permalink
Merge pull request #146 from cerebris/pr/144
Browse files Browse the repository at this point in the history
Has_many associations JSON API compliance
  • Loading branch information
dgeb committed Apr 7, 2015
2 parents 196dee2 + c7a3482 commit e39c9c4
Show file tree
Hide file tree
Showing 7 changed files with 47 additions and 6 deletions.
1 change: 1 addition & 0 deletions lib/jsonapi/error_codes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ module JSONAPI
INVALID_PAGE_VALUE = 118
INVALID_SORT_FORMAT = 119
INVALID_FIELD_FORMAT = 120
FORBIDDEN = 403
RECORD_NOT_FOUND = 404
UNSUPPORTED_MEDIA_TYPE = 415
LOCKED = 423
Expand Down
9 changes: 9 additions & 0 deletions lib/jsonapi/exceptions.rb
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,15 @@ def errors
end
end

class HasManySetReplacementForbidden < Error
def errors
[JSONAPI::Error.new(code: JSONAPI::FORBIDDEN,
status: :forbidden,
title: 'Complete replacement forbidden',
detail: 'Complete replacement forbidden for this association')]
end
end

class FilterNotAllowed < Error
attr_accessor :filter
def initialize(filter)
Expand Down
4 changes: 4 additions & 0 deletions lib/jsonapi/request.rb
Original file line number Diff line number Diff line change
Expand Up @@ -387,6 +387,10 @@ def parse_update_association_operation(data, association_type, parent_key)
association_type,
verified_param_set[:has_one].values[0])
else
unless association.acts_as_set
raise JSONAPI::Exceptions::HasManySetReplacementForbidden.new
end

object_params = {links: {association.name => {linkage: data}}}
verified_param_set = parse_params(object_params, @resource_klass.updateable_fields(@context))

Expand Down
4 changes: 1 addition & 3 deletions lib/jsonapi/resource.rb
Original file line number Diff line number Diff line change
Expand Up @@ -428,9 +428,7 @@ def _updateable_associations
associations = []

@_associations.each do |key, association|
if association.is_a?(JSONAPI::Association::HasOne) || association.acts_as_set
associations.push(key)
end
associations.push(key)
end
associations
end
Expand Down
2 changes: 1 addition & 1 deletion lib/jsonapi/routing_ext.rb
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ def jsonapi_links(*links)
action: 'create_association', association: link_type.to_s, via: [:post]
end

if methods.include?(:update) && res._association(link_type).acts_as_set
if methods.include?(:update)
match "links/#{formatted_association_name}", controller: res._type.to_s,
action: 'update_association', association: link_type.to_s, via: [:put, :patch]
end
Expand Down
6 changes: 5 additions & 1 deletion test/fixtures/comments.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,8 @@ post_2_thanks_man:
id: 3
post_id: 2
body: Thanks man. Great post. But what is JR?
author_id: 2
author_id: 2

rogue_comment:
body: Rogue Comment Here
author_id: 3
27 changes: 26 additions & 1 deletion test/integration/requests/request_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ def test_post_single

def test_update_association_without_content_type
ruby = Section.find_by(name: 'ruby')
patch '/posts/3/links/section', { 'sections' => {type: 'sections', id: ruby.id.to_s }}.to_json
patch '/posts/3/links/section', { 'data' => {type: 'sections', id: ruby.id.to_s }}.to_json

assert_equal 415, status
end
Expand All @@ -177,6 +177,31 @@ def test_put_update_association_has_one
assert_equal 204, status
end

def test_patch_update_association_has_many_acts_as_set
# Comments are acts_as_set=false so PUT/PATCH should respond with 403

rogue = Comment.find_by(body: 'Rogue Comment Here')
patch '/posts/5/links/comments', { 'data' => [{type: 'comments', id: rogue.id.to_s }]}.to_json, "CONTENT_TYPE" => JSONAPI::MEDIA_TYPE

assert_equal 403, status
end

def test_post_update_association_has_many
rogue = Comment.find_by(body: 'Rogue Comment Here')
post '/posts/5/links/comments', { 'data' => [{type: 'comments', id: rogue.id.to_s }]}.to_json, "CONTENT_TYPE" => JSONAPI::MEDIA_TYPE

assert_equal 204, status
end

def test_put_update_association_has_many_acts_as_set
# Comments are acts_as_set=false so PUT/PATCH should respond with 403. Note: JR currently treats PUT and PATCH as equivalent

rogue = Comment.find_by(body: 'Rogue Comment Here')
put '/posts/5/links/comments', { 'data' => [{type: 'comments', id: rogue.id.to_s }]}.to_json, "CONTENT_TYPE" => JSONAPI::MEDIA_TYPE

assert_equal 403, status
end

def test_index_content_type
get '/posts'
assert_match JSONAPI::MEDIA_TYPE, headers['Content-Type']
Expand Down

0 comments on commit e39c9c4

Please sign in to comment.