lib/jsonapi_mapper.rb in jsonapi_mapper-0.1.3 vs lib/jsonapi_mapper.rb in jsonapi_mapper-0.1.4
- old
+ new
@@ -64,19 +64,18 @@
end
attrs = attrs.map(&:to_sym)
scope.symbolize_keys!
- danger = scope.keys.to_set & attrs.map{|a| renamed(type_name, a) }.to_set
+ danger = scope.keys.to_set & attrs.map{|a| renamed_attr(type_name, a) }.to_set
if danger.count > 0
raise RulesError.new("Don't let user set the scope: #{danger.to_a}")
end
- cls = renames.fetch(:types, {})[type_name] ||
- type_name.to_s.singularize.camelize.constantize
+ cls = renamed_type(type_name)
- attrs.map{|a| renamed(type_name, a) }.each do |attr|
+ attrs.map{|a| renamed_attr(type_name, a) }.each do |attr|
unless cls.new.respond_to?(attr)
raise NoMethodError.new("undefined method #{attr} for #{cls}")
end
end
@@ -101,22 +100,21 @@
end
relationships = {}
json.fetch(:relationships, {}).each do |name, value|
next unless type.rule.attributes.include?(name)
- relationships[renamed(type.name, name)] = if value[:data].is_a?(Array)
+ relationships[renamed_attr(type.name, name)] = if value[:data].is_a?(Array)
value[:data].map{|v| build_id(v) }
else
build_id(value[:data])
end
end
- if attributes_to_be_set = json[:attributes]
+ if new_values = json[:attributes]
type.rule.attributes.each do |name|
- if value = attributes_to_be_set[name]
- object.send("#{renamed(type.name, name)}=", value)
- end
+ next unless new_values.has_key?(name)
+ object.send("#{renamed_attr(type.name, name)}=", new_values[name])
end
end
resource = Resource.new(object, relationships, build_id(json))
resources[resource.id] = resource
@@ -147,24 +145,43 @@
type.class.where(type.rule.scope).find(id.raw) or
raise ActiveRecord::RecordNotFound
.new("Couldn't find #{id.type} with id=#{id.raw}")
end
- def renamed(type, attr)
+ def renamed_type(type_name)
+ renames.fetch(:types, {})[type_name] ||
+ type_name.to_s.singularize.camelize.constantize
+ end
+
+ def unrenamed_type(type)
+ type_name = type.to_s.underscore.pluralize
+ renames.fetch(:types, {}).find{|k,v| v == type }.try(:first) || type_name
+ end
+
+ def renamed_attr(type, attr)
renames.fetch(:attributes, {}).fetch(type, {}).fetch(attr, attr)
end
+ def unrenamed_attr(type_name, attr)
+ renames.fetch(:attributes, {}).fetch(type_name, {})
+ .find{|k,v| v == attr }.try(:first) || attr
+ end
+
def all
(data_mappable + included)
end
def save_all
return false unless all.all?(&:valid?)
all.each(&:save)
true
end
+ def all_valid?
+ all.map(&:valid?).all? # This does not short-circuit, to get all errors.
+ end
+
def collection?
data.is_a?(Array)
end
def single?
@@ -179,8 +196,47 @@
all.select{|o| o.is_a?(cls)}.map(&blk)
end
def data_mappable
collection? ? data : [data].compact
+ end
+
+ def all_errors
+ errors = []
+
+ if collection?
+ data.each_with_index do |resource, i|
+ errors << serialize_errors_for("/data/#{i}", resource)
+ end
+ else
+ errors << serialize_errors_for("/data", data)
+ end
+
+ included.each_with_index do |resource, i|
+ errors << serialize_errors_for("/included/#{i}", resource)
+ end
+
+ { errors: errors.flatten.compact }
+ end
+
+ private
+
+ def serialize_errors_for(prefix, model)
+ return if model.errors.empty?
+ model.errors.collect do |attr, value|
+ type_name = unrenamed_type(model.class)
+ meta = { type: type_name.to_s }
+ meta[:id] = model.id if model.id
+ {
+ status: 422,
+ title: value,
+ detail: value,
+ code: value.parameterize.underscore,
+ meta: meta,
+ source: {
+ pointer: "#{prefix}/attributes/#{unrenamed_attr(type_name, attr)}"
+ }
+ }
+ end
end
end
end