lib/jsonapi/resource.rb in jsonapi-resources-0.0.16 vs lib/jsonapi/resource.rb in jsonapi-resources-0.1.0

- old
+ new

@@ -1,84 +1,193 @@ require 'jsonapi/configuration' require 'jsonapi/resource_for' require 'jsonapi/association' +require 'jsonapi/callbacks' module JSONAPI class Resource include ResourceFor + include Callbacks @@resource_types = {} attr :context attr_reader :model + define_jsonapi_resources_callbacks :create, + :update, + :remove, + :save, + :create_has_many_link, + :replace_has_many_links, + :create_has_one_link, + :replace_has_one_link, + :remove_has_many_link, + :remove_has_one_link, + :replace_fields + def initialize(model, context = nil) @model = model @context = context end - def remove - @model.destroy - end - def id model.send(self.class._primary_key) end - def create_has_many_link(association_type, association_key_value) - association = self.class._associations[association_type] - related_resource = self.class.resource_for(association.type).find_by_key(association_key_value, context: @context) + def is_new? + id.nil? + end - # ToDo: Add option to skip relations that already exist instead of returning an error? - relation = @model.send(association.type).where(association.primary_key => association_key_value).first - if relation.nil? - @model.send(association.type) << related_resource.model + def change(callback) + if @changing + run_callbacks callback do + yield + end else - raise JSONAPI::Exceptions::HasManyRelationExists.new(association_key_value) + run_callbacks is_new? ? :create : :update do + @changing = true + run_callbacks callback do + yield + save if @save_needed + end + end end end + def remove + run_callbacks :remove do + _remove + end + end + + def create_has_many_links(association_type, association_key_values) + change :create_has_many_link do + _create_has_many_links(association_type, association_key_values) + end + end + def replace_has_many_links(association_type, association_key_values) + 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 + + def remove_has_many_link(association_type, key) + change :remove_has_many_link do + _remove_has_many_link(association_type, key) + end + end + + def remove_has_one_link(association_type) + change :remove_has_one_link do + _remove_has_one_link(association_type) + end + end + + def replace_fields(field_data) + 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 + end + + private + def save + run_callbacks :save do + _save + end + end + + def _save + @model.save! + @save_needed = false + rescue ActiveRecord::RecordInvalid => e + raise JSONAPI::Exceptions::ValidationErrors.new(e.record.errors.messages) + end + + def _remove + @model.destroy + end + + def _create_has_many_links(association_type, association_key_values) association = self.class._associations[association_type] + association_key_values.each do |association_key_value| + related_resource = self.class.resource_for(association.type).find_by_key(association_key_value, context: @context) + + # ToDo: Add option to skip relations that already exist instead of returning an error? + relation = @model.send(association.type).where(association.primary_key => association_key_value).first + if relation.nil? + @model.send(association.type) << related_resource.model + else + raise JSONAPI::Exceptions::HasManyRelationExists.new(association_key_value) + end + end + end + + def _replace_has_many_links(association_type, association_key_values) + association = self.class._associations[association_type] + send("#{association.foreign_key}=", association_key_values) + @save_needed = true end - def create_has_one_link(association_type, association_key_value) + 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) + 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 end - def remove_has_many_link(association_type, key) + def _remove_has_many_link(association_type, key) association = self.class._associations[association_type] @model.send(association.type).delete(key) end - def remove_has_one_link(association_type) + def _remove_has_one_link(association_type) association = self.class._associations[association_type] send("#{association.foreign_key}=", nil) + @save_needed = true end - def replace_fields(field_data) + def _replace_fields(field_data) field_data[:attributes].each do |attribute, value| begin send "#{attribute}=", value + @save_needed = true rescue ArgumentError # :nocov: Will be thrown if an enum value isn't allowed for an enum. Currently not tested as enums are a rails 4.1 and higher feature raise JSONAPI::Exceptions::InvalidFieldValue.new(attribute, value) # :nocov: end @@ -93,20 +202,9 @@ end if field_data[:has_one] field_data[:has_many].each do |association_type, values| replace_has_many_links(association_type, values) end if field_data[:has_many] - end - - def save - @model.save! - rescue ActiveRecord::RecordInvalid => e - raise JSONAPI::Exceptions::ValidationErrors.new(e.record.errors.messages) - end - - # Override this on a resource instance to override the fetchable keys - def fetchable_fields - self.class.fields end class << self def inherited(base) base._attributes = (_attributes || {}).dup