From f74224974fa7906c2e6cb7be701f8bde2b966e0c Mon Sep 17 00:00:00 2001 From: Larry Gebhardt Date: Tue, 15 Mar 2016 11:23:12 -0400 Subject: [PATCH 1/3] Comment the relationship record logic --- lib/railsapi/resource_relationships.rb | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/lib/railsapi/resource_relationships.rb b/lib/railsapi/resource_relationships.rb index ee102c4..843cca6 100644 --- a/lib/railsapi/resource_relationships.rb +++ b/lib/railsapi/resource_relationships.rb @@ -82,17 +82,27 @@ def _add_relationship(klass, *attrs) @_relationships[relationship_name] = relationship = klass.new(relationship_name, options) - associated_records_method_name = case relationship - when RailsAPI::Relationship::ToOne then "record_for_#{relationship_name}" - when RailsAPI::Relationship::ToMany then "records_for_#{relationship_name}" - end - foreign_key = relationship.foreign_key define_method "#{foreign_key}=" do |value| @model.method("#{foreign_key}=").call(value) end unless method_defined?("#{foreign_key}=") + # Resources for relationships are returned through the dynamically generated method named for the + # relationship (for example `has_many :comments` will create a method named `comments` on the resource). This + # method must return a single Resource for a `has_one` and an array of Resources for a `has_many` + # relationship. + # + # In addition ActiveRecord Relation records for each relationship are retrieved through a dynamically + # generated method named for the relationship (`record(s)_for_). This in turn calls + # the standard `records_for` method, which can be overridden for common code related to retrieving related + # records. + + associated_records_method_name = case relationship + when RailsAPI::Relationship::ToOne then "record_for_#{relationship_name}" + when RailsAPI::Relationship::ToMany then "records_for_#{relationship_name}" + end + define_method associated_records_method_name do relationship = self.class._relationships[relationship_name] relation_name = relationship.relation_name(context: @context) From 559eaa7e763ba6195f4ebaa72a9038629ba29e92 Mon Sep 17 00:00:00 2001 From: Larry Gebhardt Date: Tue, 15 Mar 2016 11:23:50 -0400 Subject: [PATCH 2/3] Add `is_active_record_model?` method --- lib/railsapi/resource.rb | 4 ++++ lib/railsapi/resource_relationships.rb | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/railsapi/resource.rb b/lib/railsapi/resource.rb index ddd08c6..655a826 100644 --- a/lib/railsapi/resource.rb +++ b/lib/railsapi/resource.rb @@ -310,6 +310,10 @@ def module_path private + def is_active_record_model? + _model_class && _model_class.ancestors.collect{|ancestor| ancestor.name}.include?('ActiveRecord::Base') + end + def check_reserved_resource_name(type, name) if [:ids, :types, :hrefs, :links].include?(type) warn "[NAME COLLISION] `#{name}` is a reserved resource name." diff --git a/lib/railsapi/resource_relationships.rb b/lib/railsapi/resource_relationships.rb index 843cca6..7db1387 100644 --- a/lib/railsapi/resource_relationships.rb +++ b/lib/railsapi/resource_relationships.rb @@ -73,7 +73,7 @@ def _add_relationship(klass, *attrs) check_reserved_relationship_name(relationship_name) # Initialize from an ActiveRecord model's properties - if _model_class && _model_class.ancestors.collect{|ancestor| ancestor.name}.include?('ActiveRecord::Base') + if is_active_record_model? model_association = _model_class.reflect_on_association(relationship_name) if model_association options[:class_name] ||= model_association.class_name From f2458751bfc215cbe68e807be5b0df1ba1741cd0 Mon Sep 17 00:00:00 2001 From: Larry Gebhardt Date: Fri, 18 Mar 2016 11:14:23 -0400 Subject: [PATCH 3/3] Removed includes, pagination, sorting, and filtering concerns. These belong in higher level libraries such as JSONAPI-Resources. A new method named `records_for_relationship` allows JR to implement these concerns. Breaking change: and `options` hash was added to the dynamically generated method `associated_records_method_name` (e.g. `records_for_comments`). This method was also reworked to use the above `records_for_relationship` method. --- lib/railsapi/resource.rb | 2 -- lib/railsapi/resource_records.rb | 27 -------------------------- lib/railsapi/resource_relationships.rb | 17 ++++++++-------- 3 files changed, 9 insertions(+), 37 deletions(-) delete mode 100644 lib/railsapi/resource_records.rb diff --git a/lib/railsapi/resource.rb b/lib/railsapi/resource.rb index 655a826..6100e1b 100644 --- a/lib/railsapi/resource.rb +++ b/lib/railsapi/resource.rb @@ -2,7 +2,6 @@ require 'railsapi/resource_relationships' require 'railsapi/resource_attributes' require 'railsapi/resource_fields' -require 'railsapi/resource_records' module RailsAPI class Resource @@ -10,7 +9,6 @@ class Resource include ResourceRelationships include ResourceAttributes include ResourceFields - include ResourceRecords attr_reader :context diff --git a/lib/railsapi/resource_records.rb b/lib/railsapi/resource_records.rb deleted file mode 100644 index 09104fc..0000000 --- a/lib/railsapi/resource_records.rb +++ /dev/null @@ -1,27 +0,0 @@ -module RailsAPI - module ResourceRecords - def self.included(base) - base.class_eval do - base.extend ClassMethods - end - end - - module ClassMethods - def apply_includes(records, _options = {}) - records - end - - def apply_pagination(records, _options = {}) - records - end - - def apply_sort(records, _options = {}) - records - end - - def apply_filters(records, _options = {}) - records - end - end - end -end \ No newline at end of file diff --git a/lib/railsapi/resource_relationships.rb b/lib/railsapi/resource_relationships.rb index 7db1387..5a16cad 100644 --- a/lib/railsapi/resource_relationships.rb +++ b/lib/railsapi/resource_relationships.rb @@ -103,10 +103,8 @@ def _add_relationship(klass, *attrs) when RailsAPI::Relationship::ToMany then "records_for_#{relationship_name}" end - define_method associated_records_method_name do - relationship = self.class._relationships[relationship_name] - relation_name = relationship.relation_name(context: @context) - records_for(relation_name) + define_method associated_records_method_name do |options = {}| + records_for_relationship(relationship_name, options) end unless method_defined?(associated_records_method_name) if relationship.is_a?(RailsAPI::Relationship::ToOne) @@ -161,11 +159,8 @@ def _add_relationship(klass, *attrs) relationship = self.class._relationships[relationship_name] resource_klass = relationship.resource_klass - records = public_send(associated_records_method_name) - records = resource_klass.apply_filters(records, options) - records = resource_klass.apply_sort(records, options) - records = resource_klass.apply_pagination(records, options) + records = public_send(associated_records_method_name, options) return records.collect do |record| if relationship.polymorphic? @@ -229,6 +224,12 @@ def records_for(relation_name) _model.public_send relation_name end + def records_for_relationship(relationship_name, _options = {}) + relationship = self.class._relationships[relationship_name] + relation_name = relationship.relation_name(context: @context) + records_for(relation_name) + end + private def _create_to_many_links(relationship_type, relationship_key_values) relationship = self.class._relationships[relationship_type]