Class: ApiResource::Base
- Inherits:
-
Object
- Object
- ApiResource::Base
- Extended by:
- ActiveModel::Naming
- Includes:
- AssociationActivation, Attributes, Callbacks, Conditions, Finders, ModelErrors, Observing, Scopes, Typecast
- Defined in:
- lib/api_resource/base.rb,
lib/api_resource/base.rb
Direct Known Subclasses
Constant Summary
Constants included from Typecast
Typecast::FALSE_VALUES, Typecast::ISO_DATE, Typecast::ISO_DATETIME, Typecast::TRUE_VALUES
Class Attribute Summary collapse
-
.collection_name ⇒ Object
collection_name with default.
-
.element_name ⇒ Object
element_name with default.
Class Method Summary collapse
- .build(attributes = {}) ⇒ Object
- .collection_path(prefix_options = {}, query_options = nil) ⇒ Object
-
.connection(refresh = false) ⇒ Connection
Accessor for the connection.
- .create(attributes = {}) ⇒ Object
-
.delete(id, options = {}) ⇒ Object
Deletes the resources with the ID in the +id+ parameter.
-
.element_path(id, prefix_options = {}, query_options = nil) ⇒ Object
alias_method :set_prefix, :prefix= alias_method :set_element_name, :element_name= alias_method :set_collection_name, :collection_name=.
-
.format_with_mimetype_or_format_set=(mime_type_or_format) ⇒ MimeType
Handles the setting of format to a MimeType.
-
.headers ⇒ Hash
Reader for headers.
- .inherited(klass) ⇒ Object
-
.load_resource_definition ⇒ Boolean
Explicit call to load the resource definition.
-
.new_element_path(prefix_options = {}) ⇒ Object
path to find.
-
.open_timeout_with_connection_reset=(timeout) ⇒ Fixnum
Set the open timeout on the connection and connect.
-
.prefix(options = {}) ⇒ String
Prefix for the resource path.
- .prefix=(value = '/') ⇒ Object
- .prefix_source ⇒ Object
-
.reload_resource_definition ⇒ Boolean
(also: reload_class_attributes)
Clear the old resource definition and reload it from the server.
-
.reset_connection ⇒ Boolean
Reset our connection instance so that we will reconnect the next time we need it.
-
.resource_definition ⇒ Hash?
Reader for the resource_definition.
-
.resource_definition_is_invalid? ⇒ Boolean
do we have an invalid resource.
-
.resource_definition_mutex ⇒ Mutex
Mutex so that multiple Threads don't try to load the resource definition at the same time.
-
.respond_to?(*args) ⇒ Boolean
Load our resource definition to make sure we know what this class responds to.
-
.set_class_attributes_upon_load ⇒ Boolean
This makes a request to new_element_path and sets up the correct attribute, scope and association methods for this class.
-
.site_with_connection_reset=(site) ⇒ String
Handles the setting of site while reloading the resource definition to ensure we have the latest definition.
-
.split_options(options = {}) ⇒ Object
and the other containing the leftovers.
-
.timeout_with_connection_reset=(timeout) ⇒ Fixnum
Set the timeout on the connection and connect.
-
.token_with_new_token_set=(new_token) ⇒ String
Handles the setting of tokens on descendants.
Instance Method Summary collapse
- #==(other) ⇒ Object
- #destroy ⇒ Object
- #dup ⇒ Object
- #encode(options = {}) ⇒ Object
- #eql?(other) ⇒ Boolean
- #hash ⇒ Object
- #id ⇒ Object
-
#id=(id) ⇒ Object
Bypass dirty tracking for this field.
-
#initialize(attributes = {}) ⇒ Base
constructor
A new instance of Base.
- #new? ⇒ Boolean (also: #new_record?)
- #persisted? ⇒ Boolean
- #prefix_attribute_names ⇒ Object
- #prefix_options ⇒ Object
- #reload ⇒ Object
- #save(*args) ⇒ Object
- #save!(*args) ⇒ Object
-
#serializable_hash(options = {}) ⇒ Object
TODO: (Updated 10/26/2013): Leaving this old message here though the behavior is now in Serializer.
- #to_json(options = {}) ⇒ Object
-
#to_key ⇒ Array<Fixnum>?
Implementation of to_key for use in Rails forms.
- #to_param ⇒ Object
-
#to_s ⇒ Object
(also: #inspect)
Override to_s and inspect so they only show attributes and not associations, this prevents force loading of associations when we call to_s or inspect on a descendent of base but allows it if we try to evaluate an association directly.
-
#to_xml(options = {}) ⇒ Object
Methods for serialization as json or xml, relying on the serializable_hash method.
- #update_attributes(attrs) ⇒ Object
Methods included from Scopes
#scope?, #scope_attributes, #scopes
Methods included from Callbacks
#create_with_callbacks, #destroy_with_callbacks, #save_with_callbacks, #update_with_callbacks
Methods included from Observing
Methods included from Attributes
#[], #[]=, #attribute?, #attributes, #attributes=, #clear_changes, #make_changes_current, #method_missing, #protected_attribute?, #public_attribute?, #read_attribute, #read_attribute_before_type_cast, #reset_changes, #respond_to?, #save_with_dirty_tracking, #typecast_attribute_for_read, #typecast_attribute_for_write, #write_attribute
Methods included from ModelErrors
#errors, #load_remote_errors, #save_with_validations, #valid?
Constructor Details
#initialize(attributes = {}) ⇒ Base
Returns a new instance of Base.
513 514 515 516 517 518 519 520 521 |
# File 'lib/api_resource/base.rb', line 513 def initialize(attributes = {}) # call super's initialize to set up any variables that we need super(attributes) # if we initialize this class, load the attributes self.class.load_resource_definition # Now we can make a call to setup the inheriting # klass with its attributes self.attributes = attributes end |
Dynamic Method Handling
This class handles dynamic methods through the method_missing method in the class ApiResource::Attributes
Class Attribute Details
.collection_name ⇒ Object
collection_name with default
354 355 356 |
# File 'lib/api_resource/base.rb', line 354 def collection_name @collection_name ||= ActiveSupport::Inflector.pluralize(self.element_name) end |
.element_name ⇒ Object
element_name with default
350 351 352 |
# File 'lib/api_resource/base.rb', line 350 def element_name @element_name ||= self.model_name.element end |
Class Method Details
.build(attributes = {}) ⇒ Object
395 396 397 |
# File 'lib/api_resource/base.rb', line 395 def build(attributes = {}) self.new(attributes) end |
.collection_path(prefix_options = {}, query_options = nil) ⇒ Object
388 389 390 391 392 393 |
# File 'lib/api_resource/base.rb', line 388 def collection_path( = {}, = nil) , = () if .nil? # Fall back on this rather than search without the id "#{prefix()}#{collection_name}.#{format.extension}#{query_string()}" end |
.connection(refresh = false) ⇒ Connection
Accessor for the connection
80 81 82 83 84 85 86 |
# File 'lib/api_resource/base.rb', line 80 def connection(refresh = false) if refresh || @connection.nil? @connection = Connection.new(self.site, self.format, self.headers) end @connection.timeout = self.timeout @connection end |
.create(attributes = {}) ⇒ Object
399 400 401 |
# File 'lib/api_resource/base.rb', line 399 def create(attributes = {}) self.new(attributes).tap{ |resource| resource.save } end |
.delete(id, options = {}) ⇒ Object
Deletes the resources with the ID in the +id+ parameter.
==== Options All options specify \prefix and query parameters.
==== Examples Event.delete(2) # sends DELETE /events/2
Event.create(name: 'Free Concert', location: 'Community Center') my_event = Event.find(:first) # let's assume this is event with ID 7 Event.delete(my_event.id) # sends DELETE /events/7
# Let's assume a request to events/5/cancel.xml Event.delete(params[:id]) # sends DELETE /events/5
418 419 420 |
# File 'lib/api_resource/base.rb', line 418 def delete(id, = {}) connection.delete(element_path(id, )) end |
.element_path(id, prefix_options = {}, query_options = nil) ⇒ Object
alias_method :set_prefix, :prefix= alias_method :set_element_name, :element_name= alias_method :set_collection_name, :collection_name=
362 363 364 365 366 367 368 369 370 371 372 373 |
# File 'lib/api_resource/base.rb', line 362 def element_path(id, = {}, = nil) , = () if .nil? # If we have a prefix, we need a foreign key id # This regex detects '//', which means no foreign key id is present. if prefix() =~ /\/\/$/ "/#{collection_name}/#{URI.escape id.to_s}.#{format.extension}#{query_string()}" else # Fall back on this rather than search without the id "#{prefix()}#{collection_name}/#{URI.escape id.to_s}.#{format.extension}#{query_string()}" end end |
.format_with_mimetype_or_format_set=(mime_type_or_format) ⇒ MimeType
Handles the setting of format to a MimeType
94 95 96 97 98 99 100 101 102 103 104 105 |
# File 'lib/api_resource/base.rb', line 94 def format_with_mimetype_or_format_set=(mime_type_or_format) if mime_type_or_format.is_a?(Symbol) format = ApiResource::Formats[mime_type_or_format] else format = mime_type_or_format end self.format_without_mimetype_or_format_set = format if self.site self.connection.format = format end format end |
.headers ⇒ Hash
Reader for headers
112 113 114 115 116 |
# File 'lib/api_resource/base.rb', line 112 def headers {}.tap do |ret| ret['Lifebooker-Token'] = self.token if self.token.present? end end |
.inherited(klass) ⇒ Object
118 119 120 121 122 123 124 125 126 127 128 129 130 |
# File 'lib/api_resource/base.rb', line 118 def inherited(klass) # Call the methods of the superclass to make sure inheritable accessors and the like have been inherited super # Now we need to define the inherited method on the klass that's doing the inheriting # it calls super which will allow the chaining effect we need klass.instance_eval <<-EOE, __FILE__, __LINE__ + 1 def inherited(klass) klass.send(:define_singleton_method, :collection_name, lambda {self.superclass.collection_name}) super(klass) end EOE true end |
.load_resource_definition ⇒ Boolean
Explicit call to load the resource definition
loaded
137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 |
# File 'lib/api_resource/base.rb', line 137 def load_resource_definition unless instance_variable_defined?(:@resource_definition) # Lock the mutex to make sure only one thread does # this at a time self.resource_definition_mutex.synchronize do # once we have the lock, check to make sure the resource # definition wasn't fetched while we were sleeping return true if instance_variable_defined?(:@resource_definition) # the last time we checked @resource_load_time = Time.now # set to not nil so we don't get an infinite loop @resource_definition = true self.set_class_attributes_upon_load return true end end # we didn't do anything false end |
.new_element_path(prefix_options = {}) ⇒ Object
path to find
376 377 378 379 380 381 382 383 384 385 386 |
# File 'lib/api_resource/base.rb', line 376 def new_element_path( = {}) url = File.join( self.prefix(), self.collection_name, "new.#{format.extension}" ) if self.superclass != ApiResource::Base && self.name.present? url = "#{url}?type=#{self.name.demodulize}" end return url end |
.open_timeout_with_connection_reset=(timeout) ⇒ Fixnum
Set the open timeout on the connection and connect
164 165 166 167 |
# File 'lib/api_resource/base.rb', line 164 def open_timeout_with_connection_reset=(timeout) @connection = nil self.open_timeout_without_connection_reset = timeout end |
.prefix(options = {}) ⇒ String
Are the options used?
Prefix for the resource path
178 179 180 181 182 183 |
# File 'lib/api_resource/base.rb', line 178 def prefix( = {}) default = (self.site ? self.site.path : '/') default << '/' unless default[-1..-1] == '/' self.prefix = default prefix() end |
.prefix=(value = '/') ⇒ Object
330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 |
# File 'lib/api_resource/base.rb', line 330 def prefix=(value = '/') prefix_call = value.gsub(/:\w+/) { |key| "\#{URI.escape options[#{key}].to_s}" } @prefix_parameters = nil silence_warnings do instance_eval <<-EOE, __FILE__, __LINE__ + 1 def prefix_source() "#{value}" end def prefix(options={}) ret = "#{prefix_call}" ret =~ Regexp.new(Regexp.escape("//")) ? "/" : ret end EOE end rescue Exception => e logger.error "Couldn't set prefix: #{e}\n #{code}" if logger raise end |
.prefix_source ⇒ Object
Not sure what this does
187 188 189 190 |
# File 'lib/api_resource/base.rb', line 187 def prefix_source prefix prefix_source end |
.reload_resource_definition ⇒ Boolean Also known as: reload_class_attributes
Clear the old resource definition and reload it from the server
197 198 199 200 201 202 203 204 205 |
# File 'lib/api_resource/base.rb', line 197 def reload_resource_definition # clear the public_attribute_names, protected_attribute_names if instance_variable_defined?(:@resource_definition) remove_instance_variable(:@resource_definition) self.clear_attributes self. end self.load_resource_definition end |
.reset_connection ⇒ Boolean
Reset our connection instance so that we will reconnect the next time we need it
223 224 225 226 |
# File 'lib/api_resource/base.rb', line 223 def reset_connection remove_instance_variable(:@connection) if @connection.present? true end |
.resource_definition ⇒ Hash?
Reader for the resource_definition
232 233 234 |
# File 'lib/api_resource/base.rb', line 232 def resource_definition @resource_definition end |
.resource_definition_is_invalid? ⇒ Boolean
do we have an invalid resource
423 424 425 426 427 428 429 430 |
# File 'lib/api_resource/base.rb', line 423 def resource_definition_is_invalid? # if we have a Hash, it's valid return false if @resource_definition.is_a?(Hash) # if we have no recheck time, it's invalid return true if @resource_load_time.nil? # have we checked in the last minute? return @resource_load_time < Time.now - 1.minute end |
.resource_definition_mutex ⇒ Mutex
Mutex so that multiple Threads don't try to load the resource definition at the same time
214 215 216 |
# File 'lib/api_resource/base.rb', line 214 def resource_definition_mutex @resource_definition_mutex ||= Mutex.new end |
.respond_to?(*args) ⇒ Boolean
Load our resource definition to make sure we know what this class responds to
241 242 243 244 |
# File 'lib/api_resource/base.rb', line 241 def respond_to?(*args) self.load_resource_definition super end |
.set_class_attributes_upon_load ⇒ Boolean
This makes a request to new_element_path and sets up the correct attribute, scope and association methods for this class
251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 |
# File 'lib/api_resource/base.rb', line 251 def set_class_attributes_upon_load # this only happens in subclasses return true if self == ApiResource::Base begin @resource_definition = self.connection.get( self.new_element_path, self.headers ) # set up methods derived from our class definition self.define_all_attributes self.define_all_scopes self.define_all_associations # Swallow up any loading errors because the site may be incorrect rescue Exception => e self.handle_resource_definition_error(e) end true end |
.site_with_connection_reset=(site) ⇒ String
Handles the setting of site while reloading the resource definition to ensure we have the latest definition
277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 |
# File 'lib/api_resource/base.rb', line 277 def site_with_connection_reset=(site) # store so we can reload attributes if the site changed old_site = self.site.to_s.clone @connection = nil if site.nil? self.site_without_connection_reset = nil # no site, so we'll skip the reload return site else self.site_without_connection_reset = create_site_uri_from(site) end # reset class attributes and try to reload them if the site changed unless self.site.to_s == old_site self.reload_resource_definition end return site end |
.split_options(options = {}) ⇒ Object
and the other containing the leftovers.
434 435 436 437 438 439 440 441 442 |
# File 'lib/api_resource/base.rb', line 434 def ( = {}) , = {}, {} ( || {}).each do |key, value| next if key.blank? (prefix_parameters.include?(key.to_sym) ? : )[key.to_sym] = value end [ , ] end |
.timeout_with_connection_reset=(timeout) ⇒ Fixnum
Set the timeout on the connection and connect
305 306 307 308 |
# File 'lib/api_resource/base.rb', line 305 def timeout_with_connection_reset=(timeout) @connection = nil self.timeout_without_connection_reset = timeout end |
.token_with_new_token_set=(new_token) ⇒ String
Handles the setting of tokens on descendants
317 318 319 320 321 322 323 324 |
# File 'lib/api_resource/base.rb', line 317 def token_with_new_token_set=(new_token) self.token_without_new_token_set = new_token self.connection(true) self.descendants.each do |child| child.send(:token=, new_token) end new_token end |
Instance Method Details
#==(other) ⇒ Object
541 542 543 |
# File 'lib/api_resource/base.rb', line 541 def ==(other) other.equal?(self) || (other.instance_of?(self.class) && other.id == self.id) end |
#destroy ⇒ Object
578 579 580 |
# File 'lib/api_resource/base.rb', line 578 def destroy connection.delete(element_path(self.id), self.class.headers) end |
#dup ⇒ Object
553 554 555 |
# File 'lib/api_resource/base.rb', line 553 def dup self.class.instantiate_record(self.attributes) end |
#encode(options = {}) ⇒ Object
582 583 584 |
# File 'lib/api_resource/base.rb', line 582 def encode( = {}) self.send("to_#{self.class.format.extension}", ) end |
#eql?(other) ⇒ Boolean
545 546 547 |
# File 'lib/api_resource/base.rb', line 545 def eql?(other) self == other end |
#hash ⇒ Object
549 550 551 |
# File 'lib/api_resource/base.rb', line 549 def hash id.hash end |
#id ⇒ Object
532 533 534 |
# File 'lib/api_resource/base.rb', line 532 def id self.read_attribute(self.class.primary_key) end |
#id=(id) ⇒ Object
Bypass dirty tracking for this field
537 538 539 |
# File 'lib/api_resource/base.rb', line 537 def id=(id) @attributes[self.class.primary_key] = id end |
#new? ⇒ Boolean Also known as: new_record?
523 524 525 |
# File 'lib/api_resource/base.rb', line 523 def new? id.blank? end |
#persisted? ⇒ Boolean
528 529 530 |
# File 'lib/api_resource/base.rb', line 528 def persisted? !new? end |
#prefix_attribute_names ⇒ Object
613 614 615 616 |
# File 'lib/api_resource/base.rb', line 613 def prefix_attribute_names return [] unless self.class.prefix_source =~ /\:/ self.class.prefix_source.scan(/\:(\w+)/).collect{|match| match.first.to_sym} end |
#prefix_options ⇒ Object
604 605 606 607 608 609 610 611 |
# File 'lib/api_resource/base.rb', line 604 def return {} unless self.class.prefix_source =~ /\:/ ret = {} self.prefix_attribute_names.each do |name| ret[name] = self.send(name) end ret end |
#reload ⇒ Object
586 587 588 589 590 591 592 593 594 595 596 |
# File 'lib/api_resource/base.rb', line 586 def reload # find the record from the remote service reloaded = self.class.find(self.id) # clear out the attributes cache @attributes_cache = HashWithIndifferentAccess.new # set up our attributes cache on our record @attributes = reloaded.instance_variable_get(:@attributes) reloaded end |
#save(*args) ⇒ Object
570 571 572 |
# File 'lib/api_resource/base.rb', line 570 def save(*args) new? ? create(*args) : update(*args) end |
#save!(*args) ⇒ Object
574 575 576 |
# File 'lib/api_resource/base.rb', line 574 def save!(*args) save(*args) || raise(ApiResource::ResourceInvalid.new(self)) end |
#serializable_hash(options = {}) ⇒ Object
TODO: (Updated 10/26/2013): Leaving this old message here though the behavior is now in Serializer. Any changes should be done there
this method needs to change seriously to fit in with the new typecasting scheme, it should call self.outgoing_attributes which should return the converted versions after calling to_api, that should be implemented in the attributes module though
652 653 654 |
# File 'lib/api_resource/base.rb', line 652 def serializable_hash( = {}) return Serializer.new(self, ).to_hash end |
#to_json(options = {}) ⇒ Object
632 633 634 635 636 637 638 639 640 641 642 |
# File 'lib/api_resource/base.rb', line 632 def to_json( = {}) # handle whether or not we include root in our JSON if self.class.include_root_in_json ret = { self.class.element_name => self.serializable_hash() } else ret = self.serializable_hash() end ret.to_json end |
#to_key ⇒ Array<Fixnum>?
Implementation of to_key for use in Rails forms
561 562 563 |
# File 'lib/api_resource/base.rb', line 561 def to_key [self.id] if self.id.present? end |
#to_param ⇒ Object
598 599 600 601 602 |
# File 'lib/api_resource/base.rb', line 598 def to_param # Stolen from active_record. # We can't use alias_method here, because method 'id' optimizes itself on the fly. id && id.to_s # Be sure to stringify the id for routes end |
#to_s ⇒ Object Also known as: inspect
Override to_s and inspect so they only show attributes and not associations, this prevents force loading of associations when we call to_s or inspect on a descendent of base but allows it if we try to evaluate an association directly
622 623 624 |
# File 'lib/api_resource/base.rb', line 622 def to_s return "#<#{self.class}:#{(self.object_id * 2).to_s(16)} @attributes=#{self.attributes}" end |
#to_xml(options = {}) ⇒ Object
Methods for serialization as json or xml, relying on the serializable_hash method
628 629 630 |
# File 'lib/api_resource/base.rb', line 628 def to_xml( = {}) self.serializable_hash().to_xml(root: self.class.element_name) end |
#update_attributes(attrs) ⇒ Object
565 566 567 568 |
# File 'lib/api_resource/base.rb', line 565 def update_attributes(attrs) self.attributes = attrs self.save end |