Skip to content

Commit

Permalink
allow custom type for models
Browse files Browse the repository at this point in the history
fix #288
  • Loading branch information
senid231 committed Jan 15, 2019
1 parent 435e878 commit 7bb3959
Show file tree
Hide file tree
Showing 7 changed files with 173 additions and 0 deletions.
16 changes: 16 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -553,6 +553,22 @@ class MyApi::Base < JsonApiClient::Resource
end
```
### Custom type
If your model must be named differently from classified type of resource you can easily customize it.
It will work both for defined and not defined relationships
```ruby
class MyApi::Base < JsonApiClient::Resource
resolve_custom_type 'document--files', 'File'
end

class MyApi::File < MyApi::Base
def self.resource_name
'document--files'
end
end
```
### Type Casting
Expand Down
7 changes: 7 additions & 0 deletions lib/json_api_client/resource.rb
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ class Resource
:route_format,
:request_params_class,
:keep_request_params,
:custom_type_to_class,
instance_accessor: false
class_attribute :add_defaults_to_changes,
instance_writer: false
Expand All @@ -50,6 +51,7 @@ class Resource
self.request_params_class = RequestParams
self.keep_request_params = false
self.add_defaults_to_changes = false
self.custom_type_to_class = {}

#:underscored_key, :camelized_key, :dasherized_key, or custom
self.json_key_format = :underscored_key
Expand All @@ -61,6 +63,11 @@ class << self
extend Forwardable
def_delegators :_new_scope, :where, :order, :includes, :select, :all, :paginate, :page, :with_params, :first, :find, :last

def resolve_custom_type(type_name, class_name)
classified_type = key_formatter.unformat(type_name.to_s).singularize.classify
self.custom_type_to_class = custom_type_to_class.merge(classified_type => class_name.to_s)
end

# The table name for this resource. i.e. Article -> articles, Person -> people
#
# @return [String] The table name for this resource
Expand Down
1 change: 1 addition & 0 deletions lib/json_api_client/utils.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ module JsonApiClient
module Utils

def self.compute_type(klass, type_name)
return klass.custom_type_to_class.fetch(type_name).constantize if klass.custom_type_to_class.key?(type_name)
# If the type is prefixed with a scope operator then we assume that
# the type_name is an absolute reference.
return type_name.constantize if type_name.match(/^::/)
Expand Down
15 changes: 15 additions & 0 deletions test/test_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,21 @@ class UserPreference < TestResource
self.primary_key = :user_id
end

class DocumentUser < TestResource
resolve_custom_type 'document--files', 'DocumentFile'
end

class DocumentStore < TestResource
resolve_custom_type 'document--files', 'DocumentFile'
has_many :files, class_name: 'DocumentFile'
end

class DocumentFile < TestResource
def self.resource_name
'document--files'
end
end

def with_altered_config(resource_class, changes)
# remember and overwrite config
old_config_values = {}
Expand Down
85 changes: 85 additions & 0 deletions test/unit/association_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -765,4 +765,89 @@ def test_nested_create_from_scope
Specified.where(foo_id: 1).create
end

def test_get_with_relationship_for_model_with_custom_type
stub_request(:get, "http://example.com/document_users/1?include=file")
.to_return(headers: {content_type: "application/vnd.api+json"}, body: {
data: [
{
id: '1',
type: 'document_users',
attributes: {
name: 'John Doe'
},
relationships: {
file: {
links: {
self: 'http://example.com/document_users/1/relationships/file',
related: 'http://example.com/document_users/1/file'
},
data: {
id: '2',
type: 'document--files'
}
}
}
}
],
included: [
{
id: '2',
type: 'document--files',
attributes: {
url: 'http://example.com/downloads/2.pdf'
}
}
]
}.to_json)

user = DocumentUser.includes('file').find(1).first

assert_equal 'document--files', user.file.type
assert user.file.is_a?(DocumentFile)
end

def test_get_with_defined_relationship_for_model_with_custom_type
stub_request(:get, "http://example.com/document_stores/1?include=files")
.to_return(headers: {content_type: "application/vnd.api+json"}, body: {
data: [
{
id: '1',
type: 'document_stores',
attributes: {
name: 'store #1'
},
relationships: {
files: {
links: {
self: 'http://example.com/document_stores/1/relationships/files',
related: 'http://example.com/document_stores/1/files'
},
data: [
{
id: '2',
type: 'document--files'
}
]
}
}
}
],
included: [
{
id: '2',
type: 'document--files',
attributes: {
url: 'http://example.com/downloads/2.pdf'
}
}
]
}.to_json)

user = DocumentStore.includes('files').find(1).first

assert_equal 1, user.files.size
assert_equal 'document--files', user.files.first.type
assert user.files.first.is_a?(DocumentFile)
end

end
27 changes: 27 additions & 0 deletions test/unit/creation_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -314,4 +314,31 @@ def test_create_with_relationships_in_payload
assert_equal "1", article.id
end

def test_create_with_custom_type
stub_request(:post, 'http://example.com/document--files')
.with(headers: {content_type: 'application/vnd.api+json', accept: 'application/vnd.api+json'}, body: {
data: {
type: 'document--files',
attributes: {
url: 'http://example.com/downloads/1.pdf'
}
}
}.to_json)
.to_return(headers: {content_type: 'application/vnd.api+json'}, body: {
data: {
type: 'document--files',
id: '1',
attributes: {
url: 'http://example.com/downloads/1.pdf'
}
}
}.to_json)

file = DocumentFile.new(url: 'http://example.com/downloads/1.pdf')

assert file.save
assert file.persisted?
assert_equal '1', file.id
end

end
22 changes: 22 additions & 0 deletions test/unit/finding_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -77,4 +77,26 @@ def test_find_all
assert_equal ["2", "3"], articles.map(&:id)
end

def test_find_by_id_with_custom_type
stub_request(:get, "http://example.com/document--files/1")
.to_return(headers: {content_type: "application/vnd.api+json"}, body: {
data: {
type: "document--files",
id: "1",
attributes: {
url: 'http://example.com/downloads/1.pdf'
}
}
}.to_json)

articles = DocumentFile.find(1)

assert articles.is_a?(JsonApiClient::ResultSet)
assert_equal 1, articles.length

article = articles.first
assert_equal '1', article.id
assert_equal 'http://example.com/downloads/1.pdf', article.url
end

end

0 comments on commit 7bb3959

Please sign in to comment.