Skip to content

Commit

Permalink
define methods for properties and associations getter/setter
Browse files Browse the repository at this point in the history
undo method definition in #method_missing
  • Loading branch information
senid231 committed Sep 21, 2018
1 parent d228cad commit f5941c5
Show file tree
Hide file tree
Showing 7 changed files with 150 additions and 16 deletions.
1 change: 1 addition & 0 deletions lib/json_api_client/associations/belongs_to.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ module ClassMethods
def belongs_to(attr_name, options = {})
# self.associations = self.associations + [HasOne::Association.new(attr_name, self, options)]
self.associations += [BelongsTo::Association.new(attr_name, self, options)]
_define_association_accessor(attr_name)
end
end

Expand Down
3 changes: 2 additions & 1 deletion lib/json_api_client/associations/has_many.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,12 @@ module HasMany
module ClassMethods
def has_many(attr_name, options = {})
self.associations = self.associations + [HasMany::Association.new(attr_name, self, options)]
_define_association_accessor(attr_name)
end
end

class Association < BaseAssociation
end
end
end
end
end
3 changes: 2 additions & 1 deletion lib/json_api_client/associations/has_one.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ module HasOne
module ClassMethods
def has_one(attr_name, options = {})
self.associations += [HasOne::Association.new(attr_name, self, options)]
_define_association_accessor(attr_name)
end
end

Expand All @@ -16,4 +17,4 @@ def from_result_set(result_set)
end
end
end
end
end
7 changes: 1 addition & 6 deletions lib/json_api_client/helpers/dynamic_attributes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,7 @@ def has_attribute?(attr_name)

def method_missing(method, *args, &block)
if has_attribute?(method)
self.class.class_eval do
define_method(method) do
attributes[method]
end
end
return send(method)
return attributes[method]
end

normalized_method = safe_key_formatter.unformat(method.to_s)
Expand Down
2 changes: 1 addition & 1 deletion lib/json_api_client/included_data.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ def initialize(result_set, data)
end
end

def data_for(method_name, definition)
def data_for(_method_name, definition)
# If data is defined, pull the record from the included data
return nil unless data = definition["data"]

Expand Down
58 changes: 51 additions & 7 deletions lib/json_api_client/resource.rb
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,12 @@ def member_endpoint(name, options = {})
# @option options [Symbol] :default The default value for the property
def property(name, options = {})
schema.add(name, options)
define_method(name) do
attributes[name]
end
define_method("#{name}=") do |value|
set_attribute(name, value)
end
end

# Declare multiple properties with the same optional options
Expand All @@ -265,6 +271,18 @@ def properties(*names)
end
end

def _define_association_accessor(attr_name)
define_method(attr_name) do
relationship_definition = relationship_definition_for(attr_name)
return unless relationship_definition
relationship_data_for attr_name, relationship_definition, association_for(attr_name)
end

define_method("#{attr_name}=") do |value|
relationships.public_send("#{attr_name}=", value)
end
end

def _belongs_to_associations
associations.select{|association| association.is_a?(Associations::BelongsTo::Association) }
end
Expand Down Expand Up @@ -315,7 +333,7 @@ def initialize(params = {})
self.attributes = self.class.default_attributes.merge(params)

self.class.schema.each_property do |property|
attributes[property.name] = property.default unless attributes.has_key?(property.name) || property.default.nil?
attributes[property.name] = property.default if !attributes.has_key?(property.name) && !property.default.nil?
end

self.class.associations.each do |association|
Expand Down Expand Up @@ -480,21 +498,47 @@ def reset_request_select!(*resource_types)

protected

def relationship_definition_for(name)
relationships[name] if relationships && relationships.has_attribute?(name)
end

def included_data_for(name, relationship_definition)
last_result_set.included.data_for(name, relationship_definition)
end

def relationship_data_for(name, relationship_definition, association)
return unless relationship_definition

# look in included data
if relationship_definition.key?("data")
return included_data_for(name, relationship_definition)
end

url = relationship_definition["links"]["related"]
if relationship_definition["links"] && url
return association.data(url)
end

nil
end

def method_missing(method, *args)
association = association_for(method)
relationship_definition = relationship_definition_for(method)

return super unless association || (relationships && relationships.has_attribute?(method))
return super if association.nil? && relationship_definition.nil?

return nil unless relationship_definitions = relationships[method]
return unless relationship_definition

# look in included data
if relationship_definitions.key?("data")
return last_result_set.included.data_for(method, relationship_definitions)
if relationship_definition.key?("data")
return included_data_for(method, relationship_definition)
end

if association = association_for(method)
if association
# look for a defined relationship url
if relationship_definitions["links"] && url = relationship_definitions["links"]["related"]
url = relationship_definition["links"]["related"]
if relationship_definition["links"] && url
return association.data(url)
end
end
Expand Down
92 changes: 92 additions & 0 deletions test/unit/updating_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,49 @@ def test_can_update_single_relationship
assert article.save
end

def test_can_update_single_relationship_via_setter
articles = Article.find(1)
article = articles.first

stub_request(:patch, "http://example.com/articles/1")
.with(headers: {content_type: "application/vnd.api+json", accept: "application/vnd.api+json"}, body: {
data: {
id: "1",
type: "articles",
relationships: {
author: {
data: {
type: "people",
id: "1"
}
}
},
attributes: {}
}
}.to_json)
.to_return(headers: {status: 200, content_type: "application/vnd.api+json"}, body: {
data: {
type: "articles",
id: "1",
attributes: {
title: "Rails is Omakase"
},
relationships: {
author: {
links: {
self: "/articles/1/links/author",
related: "/articles/1/author",
},
data: { type: "people", id: "1" }
}
}
}
}.to_json)

article.author = Person.new(id: "1")
assert article.save
end

def test_can_update_single_relationship_with_all_attributes_dirty
articles = Article.find(1)
article = articles.first
Expand Down Expand Up @@ -313,6 +356,55 @@ def test_can_update_has_many_relationships
assert article.save
end

def test_can_update_has_many_relationships_via_setter
articles = Article.find(1)
article = articles.first

stub_request(:patch, "http://example.com/articles/1")
.with(headers: {content_type: "application/vnd.api+json", accept: "application/vnd.api+json"}, body: {
data: {
id: "1",
type: "articles",
relationships: {
comments: {
data: [{
type: "comments",
id: "2"
},{
type: "comments",
id: "3"
}]
}
},
attributes: {}
}
}.to_json)
.to_return(headers: {status: 200, content_type: "application/vnd.api+json"}, body: {
data: {
id: "1",
type: "articles",
relationships: {
author: {
links: {
self: "/articles/1/links/author",
related: "/articles/1/author",
},
data: { type: "people", id: "1" }
}
},
attributes: {
title: "Rails is Omakase"
}
}
}.to_json)

article.comments = [
Comment.new(id: "2"),
Comment.new(id: "3")
]
assert article.save
end

def test_can_update_has_many_relationships_with_all_attributes_dirty
articles = Article.find(1)
article = articles.first
Expand Down

0 comments on commit f5941c5

Please sign in to comment.