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