lib/jsonapi/resource.rb in jsonapi-resources-0.6.1 vs lib/jsonapi/resource.rb in jsonapi-resources-0.6.2
- old
+ new
@@ -105,21 +105,33 @@
change :replace_fields do
_replace_fields(field_data)
end
end
- # Override this on a resource instance to override the fetchable keys
def fetchable_fields
- self.class.fields
+ self.class.fetchable_fields(context)
end
# Override this on a resource to customize how the associated records
# are fetched for a model. Particularly helpful for authorization.
def records_for(relation_name)
_model.public_send relation_name
end
+ def model_error_messages
+ _model.errors.messages
+ end
+
+ # Override this to return resource level meta data
+ # must return a hash, and if the hash is empty the meta section will not be serialized with the resource
+ # meta keys will be not be formatted with the key formatter for the serializer by default. They can however use the
+ # serializer's format_key and format_value methods if desired
+ # the _options hash will contain the serializer and the serialization_options
+ def meta(_options)
+ {}
+ end
+
private
def save
run_callbacks :save do
_save
@@ -143,12 +155,18 @@
unless @model.valid?
fail JSONAPI::Exceptions::ValidationErrors.new(self)
end
if defined? @model.save
- saved = @model.save
- fail JSONAPI::Exceptions::SaveFailed.new unless saved
+ saved = @model.save(validate: false)
+ unless saved
+ if @model.errors.present?
+ fail JSONAPI::Exceptions::ValidationErrors.new(self)
+ else
+ fail JSONAPI::Exceptions::SaveFailed.new
+ end
+ end
else
saved = true
end
@save_needed = !saved
@@ -272,19 +290,43 @@
base.attribute :id, format: :id
check_reserved_resource_name(base._type, base.name)
end
- def resource_for(type)
- resource_name = JSONAPI::Resource._resource_name_from_type(type)
- resource = resource_name.safe_constantize if resource_name
- if resource.nil?
- fail NameError, "JSONAPI: Could not find resource '#{type}'. (Class #{resource_name} not found)"
+ def resource_for(resource_path)
+ unless @@resource_types.key? resource_path
+ klass_name = "#{resource_path.to_s.underscore.singularize}_resource".camelize
+ klass = (klass_name.safe_constantize or
+ fail NameError,
+ "JSONAPI: Could not find resource '#{resource_path}'. (Class #{klass_name} not found)")
+ normalized_path = resource_path.rpartition('/').first
+ normalized_model = klass._model_name.to_s.gsub(/\A::/, '')
+ @@resource_types[resource_path] = {
+ resource: klass,
+ path: normalized_path,
+ model: normalized_model,
+ }
end
- resource
+ @@resource_types[resource_path][:resource]
end
+ def resource_for_model_path(model, path)
+ normalized_model = model.class.to_s.gsub(/\A::/, '')
+ normalized_path = path.gsub(/\/\z/, '')
+ resource = @@resource_types.find { |_, h|
+ h[:path] == normalized_path && h[:model] == normalized_model
+ }
+ if resource
+ resource.last[:resource]
+ else
+ #:nocov:#
+ fail NameError,
+ "JSONAPI: Could not find resource for model '#{path}#{normalized_model}'"
+ #:nocov:#
+ end
+ end
+
attr_accessor :_attributes, :_relationships, :_allowed_filters, :_type, :_paginator
def create(context)
new(create_model, context)
end
@@ -383,10 +425,15 @@
super
end
end
# :nocov:
+ # Override in your resource to filter the fetchable keys
+ def fetchable_fields(_context = nil)
+ fields
+ end
+
# Override in your resource to filter the updatable keys
def updatable_fields(_context = nil)
_updatable_relationships | _attributes.keys - [:id]
end
@@ -501,11 +548,11 @@
records = apply_pagination(records, options[:paginator], order_options)
resources = []
records.each do |model|
- resources.push resource_for(resource_type_for(model)).new(model, context)
+ resources.push resource_for_model_path(model, self.module_path).new(model, context)
end
resources
end
@@ -513,17 +560,13 @@
context = options[:context]
records = records(options)
records = apply_includes(records, options)
model = records.where({_primary_key => key}).first
fail JSONAPI::Exceptions::RecordNotFound.new(key) if model.nil?
- resource_for(resource_type_for(model)).new(model, context)
+ resource_for_model_path(model, self.module_path).new(model, context)
end
- def resource_type_for(model)
- self.module_path + model.class.to_s.underscore
- end
-
# Override this method if you want to customize the relation for
# finder methods (find, find_by_key)
def records(_options = {})
_model_class
end
@@ -633,19 +676,10 @@
def _allowed_filters
!@_allowed_filters.nil? ? @_allowed_filters : { id: {} }
end
- def _resource_name_from_type(type)
- class_name = @@resource_types[type]
- if class_name.nil?
- class_name = "#{type.to_s.underscore.singularize}_resource".camelize
- @@resource_types[type] = class_name
- end
- return class_name
- end
-
def _paginator
@_paginator ||= JSONAPI.configuration.default_paginator
end
def paginator(paginator)
@@ -761,11 +795,11 @@
end unless method_defined?(foreign_key)
define_method attr do |options = {}|
if relationship.polymorphic?
associated_model = public_send(associated_records_method_name)
- resource_klass = Resource.resource_for(self.class.resource_type_for(associated_model)) if associated_model
+ resource_klass = self.class.resource_for_model_path(associated_model, self.class.module_path) if associated_model
return resource_klass.new(associated_model, @context) if resource_klass
else
resource_klass = relationship.resource_klass
if resource_klass
associated_model = public_send(associated_records_method_name)
@@ -814,10 +848,10 @@
if paginator
records = resource_klass.apply_pagination(records, paginator, order_options)
end
return records.collect do |record|
- resource_klass = Resource.resource_for(self.class.resource_type_for(record))
+ resource_klass = self.class.resource_for_model_path(record, self.class.module_path)
resource_klass.new(record, @context)
end
end unless method_defined?(attr)
end
end