module BraintreeRails module Persistence module ClassMethods def create(params) new(params).tap { |new_record| new_record.save } end def create!(params) new(params).tap { |new_record| new_record.save! } end def find(id) new(braintree_model_class.find(id)) end def delete(id) braintree_model_class.delete(id) end def braintree_model_class "braintree/#{braintree_model_name}".camelize.constantize end def braintree_model_name name.demodulize.underscore end end module InstanceMethods def persisted? !!persisted end def new_record? !persisted? end def reload init(self.class.braintree_model_class.find(id)) self end def save(*) run_callbacks :save do create_or_update end rescue RecordInvalid false end def save!(*) run_callbacks :save do create_or_update! end end def update_attributes(attributes) assign_attributes(attributes) save end def update_attributes!(attributes) assign_attributes(attributes) save! end def destroy if persisted? run_callbacks :destroy do self.class.delete(id) end end self.persisted = false unless frozen? freeze end def delete; destroy; end def delete!; destroy; end def destroy!; destroy; end protected def create_or_update !!(new_record? ? create : update) end def create_or_update! !!(new_record? ? create! : update!) end def create with_update_braintree(:create) do self.class.braintree_model_class.create(attributes_for(:create)) end end def create! with_update_braintree(:create) do self.class.braintree_model_class.create!(attributes_for(:create)) end end def update with_update_braintree(:update) do self.class.braintree_model_class.update(id, attributes_for(:update)) end end def update! with_update_braintree(:update) do self.class.braintree_model_class.update!(id, attributes_for(:update)) end end def with_update_braintree(context) raise RecordInvalid.new(self) unless valid?(context) run_callbacks context do case result = yield when Braintree::ErrorResult if result.respond_to?(self.class.braintree_model_name) && result.send(self.class.braintree_model_name) init(result.send(self.class.braintree_model_name)) end add_errors(result.errors) false when Braintree::SuccessfulResult init(result.send(self.class.braintree_model_name)) else init(result) end end end end def self.included(receiver) receiver.extend ActiveModel::Callbacks receiver.extend ClassMethods receiver.send :include, InstanceMethods receiver.class_eval do attr_accessor :persisted define_model_callbacks :validate, :save, :create, :update, :destroy end end end end