module StorageRoom # Abstract superclass for classes that can persist to the remote servers class Model < Resource define_model_callbacks :create, :update, :save, :destroy attr_accessor :skip_webhooks class << self # Create a new model with the passed attributes def create(attributes={}) entry = new(attributes) entry.create entry end # Get all models (could be paginated) def all load(index_path) end # Find a model with the specified id def find(id) load(show_path(id)) end # def index_path # :nodoc: raise StorageRoom::AbstractMethodError.new end def show_path(id) # :nodoc: raise StorageRoom::AbstractMethodError.new end def json_name # :nodoc: raise StorageRoom::AbstractMethodError.new end end # Create a new model and set its attributes def initialize(attributes={}) @errors = [] super end # Reset the model to its default state def reset! super @errors = [] true end # Has this model been saved to the API already? def new_record? self['@version'] ? false : true end # Create a new model or update an existing model on the server def save new_record? ? create : update end # Create a new model on the server def create return false unless new_record? _run_save_callbacks do _run_create_callbacks do httparty = self.class.post(self.class.index_path, :body => to_json, :query => query_parameters) handle_save_response(httparty) end end end # Update an existing model on the server def update return false if new_record? _run_save_callbacks do _run_update_callbacks do httparty = self.class.put(self[:@url], :body => to_json, :query => query_parameters) handle_save_response(httparty) end end end # Delete an existing model on the server def destroy return false if new_record? _run_destroy_callbacks do httparty = self.class.delete(self[:@url], :query => query_parameters) self.class.handle_critical_response_errors(httparty) end true end # Is the model valid or were there validation errors on the server? def valid? self.errors.empty? end # ActiveSupport caused problems when using as_json, so using to_hash def to_hash(args = {}) # :nodoc: args ||= {} if args[:nested] {'url' => self[:@url] || self[:url]} else hash = super hash.merge!('@version' => self['@version']) unless new_record? {self.class.json_name => hash} end end # The validation errors that were returned by the server def errors @errors ||= [] end protected def handle_save_response(httparty) # :nodoc: self.class.handle_critical_response_errors(httparty) if httparty.response.code == '200' || httparty.response.code == '201' self.set_from_response_data(httparty.parsed_response.first[1]) @errors = [] true elsif httparty.response.code == '409' # optimistic locking raise OptimisticLockingError.new("The Model has been updated by somebody else") else @errors = httparty.parsed_response['error']['message'] false end end def query_parameters skip_webhooks ? {:skip_webhooks => true} : nil end end end