lib/jsonapi/resource.rb in jsonapi-resources-0.1.1 vs lib/jsonapi/resource.rb in jsonapi-resources-0.2.0
- old
+ new
@@ -70,16 +70,10 @@
change :replace_has_many_links do
_replace_has_many_links(association_type, association_key_values)
end
end
- def create_has_one_link(association_type, association_key_value)
- change :create_has_one_link do
- _create_has_one_link(association_type, association_key_value)
- end
- end
-
def replace_has_one_link(association_type, association_key_value)
change :replace_has_one_link do
_replace_has_one_link(association_type, association_key_value)
end
end
@@ -146,23 +140,10 @@
send("#{association.foreign_key}=", association_key_values)
@save_needed = true
end
- def _create_has_one_link(association_type, association_key_value)
- association = self.class._associations[association_type]
-
- # ToDo: Add option to skip relations that already exist instead of returning an error?
- relation = @model.send("#{association.foreign_key}")
- if relation.nil?
- send("#{association.foreign_key}=", association_key_value)
- else
- raise JSONAPI::Exceptions::HasOneRelationExists.new
- end
- @save_needed = true
- end
-
def _replace_has_one_link(association_type, association_key_value)
association = self.class._associations[association_type]
send("#{association.foreign_key}=", association_key_value)
@save_needed = true
@@ -213,19 +194,21 @@
base._allowed_filters = (_allowed_filters || Set.new).dup
type = base.name.demodulize.sub(/Resource$/, '').underscore
base._type = type.pluralize.to_sym
+ base.attribute :id, format: :id
+
check_reserved_resource_name(base._type, base.name)
# If eager loading is on this is how all the resource types are setup
# If eager loading is off some resource types will be initialized in
# _resource_name_from_type
@@resource_types[base._type] ||= base.name.demodulize
end
- attr_accessor :_attributes, :_associations, :_allowed_filters , :_type
+ attr_accessor :_attributes, :_associations, :_allowed_filters , :_type, :_paginator
def create(context)
self.new(self.create_model, context)
end
@@ -249,10 +232,11 @@
end
def attribute(attr, options = {})
check_reserved_attribute_name(attr)
+ @_attributes ||= {}
@_attributes[attr] = options
define_method attr do
@model.send(attr)
end unless method_defined?(attr)
@@ -296,11 +280,11 @@
@_primary_key = key.to_sym
end
# Override in your resource to filter the updateable keys
def updateable_fields(context = nil)
- _updateable_associations | _attributes.keys
+ _updateable_associations | _attributes.keys - [_primary_key]
end
# Override in your resource to filter the createable keys
def createable_fields(context = nil)
_updateable_associations | _attributes.keys
@@ -313,38 +297,55 @@
def fields
_associations.keys | _attributes.keys
end
+ def apply_pagination(records, paginator)
+ if paginator
+ records = paginator.apply(records)
+ end
+ records
+ end
+
+ def apply_sort(records, order_options)
+ records.order(order_options)
+ end
+
def apply_filter(records, filter, value)
records.where(filter => value)
end
- # Override this method if you have more complex requirements than this basic find method provides
- def find(filters, options = {})
- context = options[:context]
- sort_params = options.fetch(:sort_params) { [] }
- includes = []
-
- records = records(options)
-
+ def apply_filters(records, filters)
+ required_includes = []
filters.each do |filter, value|
if _associations.include?(filter)
if _associations[filter].is_a?(JSONAPI::Association::HasMany)
- includes.push(filter)
+ required_includes.push(filter)
records = apply_filter(records, "#{filter}.#{_associations[filter].primary_key}", value)
else
records = apply_filter(records, "#{_associations[filter].foreign_key}", value)
end
else
records = apply_filter(records, filter, value)
end
end
+ records.includes(required_includes)
+ end
+ # Override this method if you have more complex requirements than this basic find method provides
+ def find(filters, options = {})
+ context = options[:context]
+ sort_criteria = options.fetch(:sort_criteria) { [] }
+
resources = []
- order_options = construct_order_options(sort_params)
- records.order(order_options).includes(includes).each do |model|
+
+ records = records(options)
+ records = apply_filters(records, filters)
+ records = apply_sort(records, construct_order_options(sort_criteria))
+ records = apply_pagination(records, options[:paginator])
+
+ records.each do |model|
resources.push self.new(model, context)
end
return resources
end
@@ -478,10 +479,18 @@
@@resource_types[type] = class_name
end
return class_name
end
+ def _paginator
+ @_paginator ||= JSONAPI.configuration.default_paginator
+ end
+
+ def paginator(paginator)
+ @_paginator = paginator
+ end
+
# :nocov:
if RUBY_VERSION >= '2.0'
def _model_class
@model ||= Object.const_get(_model_name.to_s)
end
@@ -498,12 +507,17 @@
def module_path
@module_path ||= self.name =~ /::[^:]+\Z/ ? ($`.freeze.gsub('::', '/') + '/').downcase : ''
end
- private
+ def construct_order_options(sort_params)
+ sort_params.each_with_object({}) { |sort, order_hash|
+ order_hash[sort[:field]] = sort[:direction]
+ }
+ end
+ private
def check_reserved_resource_name(type, name)
if [:ids, :types, :hrefs, :links].include?(type)
warn "[NAME COLLISION] `#{name}` is a reserved resource name."
return
end
@@ -549,33 +563,30 @@
associated_model = @model.send attr
return associated_model ? resource_class.new(associated_model, @context) : nil
end
end unless method_defined?(attr)
elsif @_associations[attr].is_a?(JSONAPI::Association::HasMany)
- define_method attr do
+ define_method attr do |options = {}|
type_name = self.class._associations[attr].type.to_s
resource_class = self.class.resource_for(self.class.module_path + type_name)
+ filters = options.fetch(:filters, {})
+ sort_criteria = options.fetch(:sort_criteria, {})
+ paginator = options.fetch(:paginator, nil)
+
resources = []
if resource_class
- associated_models = @model.send attr
- associated_models.each do |associated_model|
- resources.push resource_class.new(associated_model, @context)
+ records = @model.send attr
+ records = self.class.apply_filters(records, filters)
+ records = self.class.apply_sort(records, self.class.construct_order_options(sort_criteria))
+ records = self.class.apply_pagination(records, paginator)
+ records.each do |record|
+ resources.push resource_class.new(record, @context)
end
end
return resources
end unless method_defined?(attr)
end
end
- end
-
- def construct_order_options(sort_params)
- sort_params.each_with_object({}) { |sort_key, order_hash|
- if sort_key.starts_with?('-')
- order_hash[sort_key.slice(1..-1)] = :desc
- else
- order_hash[sort_key] = :asc
- end
- }
end
end
end
end