class ParseResource::Base

Constants

HashWithIndifferentAccess

Attributes

error_instances[RW]

Public Class Methods

batch_save(save_objects, slice_size = 20, method = nil) click to toggle source

Batch requests Sends multiple requests to /batch Set slice_size to send larger batches. Defaults to 20 to prevent timeouts. Parse doesn't support batches of over 20.

# File lib/parse_resource/base.rb, line 210
def self.batch_save(save_objects, slice_size = 20, method = nil)
  return true if save_objects.blank?
  load_settings
  
  base_uri = "https://api.parse.com/1/batch"
  app_id     = @@settings['app_id']
  master_key = @@settings['master_key']
  
  res = RestClient::Resource.new(base_uri, app_id, master_key)
    
  # Batch saves seem to fail if they're too big. We'll slice it up into multiple posts if they are.
  save_objects.each_slice(slice_size) do |objects|
    # attributes_for_saving
    batch_json = { "requests" => [] }
    
    objects.each do |item|
      method ||= (item.new?) ? "POST" : "PUT"
      object_path = "/1/#{item.class.model_name_uri}"
      object_path = "#{object_path}/#{item.id}" if item.id
      json = {
        "method" => method,
        "path" => object_path
      }
      json["body"] = item.attributes_for_saving unless method == "DELETE"
      batch_json["requests"] << json
    end
    res.post(batch_json.to_json, :content_type => "application/json") do |resp, req, res, &block|
      response = JSON.parse(resp) rescue nil
      if resp.code == 400
        puts resp
        return false
      end
      if response && response.is_a?(Array) && response.length == objects.length
        merge_all_attributes(objects, response) unless method == "DELETE"
      end
    end
  end
  true
end
belongs_to(parent, options = {}) click to toggle source

Similar to its ActiveRecord counterpart.

@param [Hash] options Added so that you can specify :class_name => '…'. It does nothing at all, but helps you write self-documenting code.

# File lib/parse_resource/base.rb, line 88
def self.belongs_to(parent, options = {})
  field(parent)
end
chunk(attribute) click to toggle source
# File lib/parse_resource/base.rb, line 326
def self.chunk(attribute)
  Query.new(self).chunk(attribute)
end
class_attributes() click to toggle source

Replaced with a batch destroy_all method. def self.destroy_all(all)

all.each do |object|
  object.destroy
end

end

# File lib/parse_resource/base.rb, line 348
def self.class_attributes
  @class_attributes ||= {}
end
create(attributes = {}) click to toggle source

Create a ParseResource::Base object.

@param [Hash] attributes a `Hash` of attributes @return [ParseResource] an object that subclasses `ParseResource`. Or returns `false` if object fails to save.

# File lib/parse_resource/base.rb, line 334
def self.create(attributes = {})
  attributes = HashWithIndifferentAccess.new(attributes)
  obj = new(attributes)
  obj.save
  obj
end
delete_all(o) click to toggle source
# File lib/parse_resource/base.rb, line 268
def self.delete_all(o)
  raise StandardError.new("Parse Resource: delete_all doesn't exist. Did you mean destroy_all?")
end
destroy_all(objects=nil) click to toggle source
# File lib/parse_resource/base.rb, line 263
def self.destroy_all(objects=nil)
  objects ||= self.all
  batch_save(objects, 20, "DELETE")
end
field(fname, val=nil) click to toggle source

Explicitly adds a field to the model.

@param [Symbol] name the name of the field, eg `:author`. @param [Boolean] val the return value of the field. Only use this within the class.

# File lib/parse_resource/base.rb, line 60
def self.field(fname, val=nil)
  fname = fname.to_sym
  class_eval do
    define_method(fname) do
      get_attribute("#{fname}")
    end
  end
  unless self.respond_to? "#{fname}="
    class_eval do
      define_method("#{fname}=") do |val|
        set_attribute("#{fname}", val)
        
        val
      end
    end
  end
end
fields(*args) click to toggle source

Add multiple fields in one line. Same as `#field`, but accepts multiple args.

@param [Array] *args an array of `Symbol`s, `eg :author, :body, :title`.

# File lib/parse_resource/base.rb, line 81
def self.fields(*args)
  args.each {|f| field(f)}
end
find(id) click to toggle source

Find a ParseResource::Base object by ID

@param [String] id the ID of the Parse object you want to find. @return [ParseResource] an object that subclasses ParseResource.

# File lib/parse_resource/base.rb, line 311
def self.find(id)
                    raise RecordNotFound if id.blank?
  where(:objectId => id).first
end
included(base) click to toggle source
# File lib/parse_resource/base.rb, line 547
def self.included(base)
  base.extend(ClassMethods)
end
load!(app_id, master_key) click to toggle source

Explicitly set Parse.com API keys.

@param [String] app_id the Application ID of your Parse database @param [String] master_key the Master Key of your Parse database

# File lib/parse_resource/base.rb, line 163
def self.load!(app_id, master_key)
  @@settings = {"app_id" => app_id, "master_key" => master_key}
end
load_settings() click to toggle source
# File lib/parse_resource/base.rb, line 272
def self.load_settings
  @@settings ||= begin
    path = "config/parse_resource.yml"
    environment = defined?(Rails) && Rails.respond_to?(:env) ? Rails.env : ENV["RACK_ENV"]
    YAML.load(ERB.new(File.new(path).read).result)[environment]
  end
  @@settings
end
merge_all_attributes(objects, response) click to toggle source
# File lib/parse_resource/base.rb, line 250
def self.merge_all_attributes(objects, response)
  i = 0
  objects.each do |item|
    item.merge_attributes(response[i]["success"]) if response[i] && response[i]["success"]
    i += 1
  end
  nil
end
method_missing(method_name, *args) click to toggle source
Calls superclass method
# File lib/parse_resource/base.rb, line 115
def self.method_missing(method_name, *args)
  method_name = method_name.to_s
  if method_name.start_with?("find_by_")
    attrib   = method_name.gsub(/^find_by_/,"")
    finder_name = "find_all_by_#{attrib}"

    define_singleton_method(finder_name) do |target_value|
      where({attrib.to_sym => target_value}).first
    end

    send(finder_name, args[0])

  elsif method_name.start_with?("find_all_by_")
    attrib   = method_name.gsub(/^find_all_by_/,"")
    finder_name = "find_all_by_#{attrib}"

    define_singleton_method(finder_name) do |target_value|
      where({attrib.to_sym => target_value}).all
    end

    send(finder_name, args[0])
  else
    super(method_name.to_sym, *args)
  end
end
model_base_uri() click to toggle source

Gets the current class's Parse.com base_uri

# File lib/parse_resource/base.rb, line 183
def self.model_base_uri
  "https://api.parse.com/1/#{model_name_uri}"
end
model_name_uri() click to toggle source

Gets the current class's model name for the URI

# File lib/parse_resource/base.rb, line 172
def self.model_name_uri
  if self.model_name == "User"
    "users"
  elsif self.model_name == "Installation"
    "installations"
  else
    "classes/#{self.model_name}"
  end
end
new(attributes = {}, new=true) click to toggle source

Instantiates a ParseResource::Base object

@params [Hash], [Boolean] a `Hash` of attributes and a `Boolean` that should be false only if the object already exists @return [ParseResource::Base] an object that subclasses `Parseresource::Base`

# File lib/parse_resource/base.rb, line 39
def initialize(attributes = {}, new=true)
  #attributes = HashWithIndifferentAccess.new(attributes)

  if new
    @unsaved_attributes = attributes
    @unsaved_attributes.stringify_keys!
  else
    @unsaved_attributes = {}
  end
  self.attributes = {}
  self.error_instances = []
        
  self.attributes.merge!(attributes)
  self.attributes unless self.attributes.empty?
  create_setters_and_getters!
end
resource() click to toggle source

Creates a RESTful resource sends requests to [base_uri]/

# File lib/parse_resource/base.rb, line 196
def self.resource
  load_settings

  #refactor to settings['app_id'] etc
  app_id     = @@settings['app_id']
  master_key = @@settings['master_key']
  RestClient::Resource.new(self.model_base_uri, app_id, master_key)
end
save_all(objects) click to toggle source
# File lib/parse_resource/base.rb, line 259
def self.save_all(objects)
  batch_save(objects)
end
settings() click to toggle source
# File lib/parse_resource/base.rb, line 167
def self.settings
  load_settings
end
to_date_object(date) click to toggle source
# File lib/parse_resource/base.rb, line 99
def self.to_date_object(date)
  date = date.to_time if date.respond_to?(:to_time)
  {"__type" => "Date", "iso" => date.iso8601} if date && (date.is_a?(Date) || date.is_a?(DateTime) || date.is_a?(Time))
end
upload(file_instance, filename, options={}) click to toggle source

Creates a RESTful resource for file uploads sends requests to [base_uri]/files

# File lib/parse_resource/base.rb, line 285
def self.upload(file_instance, filename, options={})
  load_settings
  
  base_uri = "https://api.parse.com/1/files"
  
  #refactor to settings['app_id'] etc
  app_id     = @@settings['app_id']
  master_key = @@settings['master_key']

  options[:content_type] ||= 'image/jpg' # TODO: Guess mime type here.
  file_instance = File.new(file_instance, 'rb') if file_instance.is_a? String

  filename = filename.parameterize

  private_resource = RestClient::Resource.new "#{base_uri}/#{filename}", app_id, master_key
  private_resource.post(file_instance, options) do |resp, req, res, &block|
    return false if resp.code == 400
    return JSON.parse(resp) rescue {"code" => 0, "error" => "unknown error"}
  end
  false
end
where(*args) click to toggle source

Find a ParseResource::Base object by chaining where method calls.

# File lib/parse_resource/base.rb, line 318
def self.where(*args)
  Query.new(self).where(*args)
end

Public Instance Methods

attributes() click to toggle source

provides access to @attributes for getting and setting

# File lib/parse_resource/base.rb, line 492
def attributes
  @attributes ||= self.class.class_attributes
  @attributes
end
attributes=(n) click to toggle source

AKN 2012-06-18: Shouldn't this also be setting @unsaved_attributes?

# File lib/parse_resource/base.rb, line 498
def attributes=(n)
  @attributes = n
  @attributes
end
attributes_for_saving() click to toggle source
# File lib/parse_resource/base.rb, line 451
def attributes_for_saving
  @unsaved_attributes = pointerize(@unsaved_attributes)
  put_attrs = @unsaved_attributes
  put_attrs.delete('objectId')
  put_attrs.delete('createdAt')
  put_attrs.delete('updatedAt')
  put_attrs
end
clean?() click to toggle source
# File lib/parse_resource/base.rb, line 487
def clean?
  !dirty?
end
create() click to toggle source
# File lib/parse_resource/base.rb, line 404
def create
  attrs = attributes_for_saving.to_json
  opts = {:content_type => "application/json"}
  result = self.resource.post(attrs, opts) do |resp, req, res, &block|
    return post_result(resp, req, res, &block)
  end
end
create_getters!(k,v) click to toggle source

Creates getter methods for model fields

# File lib/parse_resource/base.rb, line 142
def create_getters!(k,v)
  unless self.respond_to? "#{k}"
    self.class.send(:define_method, "#{k}") do
      get_attribute("#{k}")
    end
  end
end
create_setters!(k,v) click to toggle source

Creates setter methods for model fields

# File lib/parse_resource/base.rb, line 105
def create_setters!(k,v)
  unless self.respond_to? "#{k}="
    self.class.send(:define_method, "#{k}=") do |val|
      set_attribute("#{k}", val)
      
      val
    end
  end
end
create_setters_and_getters!() click to toggle source
# File lib/parse_resource/base.rb, line 150
def create_setters_and_getters!
  @attributes.each_pair do |k,v|
    create_setters!(k,v)
    create_getters!(k,v)
  end
end
created_at() click to toggle source
# File lib/parse_resource/base.rb, line 543
def created_at; get_attribute("createdAt"); end
destroy() click to toggle source
# File lib/parse_resource/base.rb, line 464
def destroy
  if self.instance_resource.delete
    @attributes = {}
    @unsaved_attributes = {}
    return true
  end
  false
end
dirty?() click to toggle source
# File lib/parse_resource/base.rb, line 483
def dirty?
  @unsaved_attributes.length > 0
end
get_attribute(k) click to toggle source
# File lib/parse_resource/base.rb, line 503
def get_attribute(k)
  attrs = @unsaved_attributes[k.to_s] ? @unsaved_attributes : @attributes
  case attrs[k]
  when Hash
    klass_name = attrs[k]["className"]
    klass_name = "User" if klass_name == "_User"
    case attrs[k]["__type"]
    when "Pointer"
      result = klass_name.constantize.find(attrs[k]["objectId"])
    when "Object"
      result = klass_name.constantize.new(attrs[k], false)
    when "Date"
      result = DateTime.parse(attrs[k]["iso"]).to_time_in_current_zone
    when "File"
      result = attrs[k]["url"]
    when "GeoPoint"
      result = ParseGeoPoint.new(attrs[k])
    end #todo: support other types https://www.parse.com/docs/rest#objects-types
  else
    result =  attrs["#{k}"]
  end          
  result
end
id() click to toggle source

aliasing for idiomatic Ruby

# File lib/parse_resource/base.rb, line 540
def id; get_attribute("objectId") rescue nil; end
instance_resource() click to toggle source

create RESTful resource for the specific Parse object sends requests to [base_uri]//[objectId]

# File lib/parse_resource/base.rb, line 371
def instance_resource
  self.class.resource["#{self.id}"]
end
merge_attributes(results) click to toggle source

Merges in the return value of a save and resets the unsaved_attributes

# File lib/parse_resource/base.rb, line 426
def merge_attributes(results)
  @attributes.merge!(results)
  @attributes.merge!(@unsaved_attributes)
  @unsaved_attributes = {}
  create_setters_and_getters!
  @attributes
end
model_base_uri() click to toggle source

Gets the current instance's parent class's Parse.com base_uri

# File lib/parse_resource/base.rb, line 188
def model_base_uri
  self.class.send(:model_base_uri)
end
new?() click to toggle source
# File lib/parse_resource/base.rb, line 360
def new?
  !persisted?
end
objectId() click to toggle source
# File lib/parse_resource/base.rb, line 541
def objectId; get_attribute("objectId") rescue nil; end
persisted?() click to toggle source
# File lib/parse_resource/base.rb, line 352
def persisted?
  if id
    true
  else
    false
  end
end
pointerize(hash) click to toggle source
# File lib/parse_resource/base.rb, line 375
def pointerize(hash)
  new_hash = {}
  hash.each do |k, v|
    if v.respond_to?(:to_pointer)
      new_hash[k] = v.to_pointer
    elsif v.is_a?(Date) || v.is_a?(Time) || v.is_a?(DateTime)
      new_hash[k] = self.class.to_date_object(v)
    else
      new_hash[k] = v
    end
  end
  new_hash
end
post_result(resp, req, res, &block) click to toggle source
# File lib/parse_resource/base.rb, line 434
def post_result(resp, req, res, &block)
  if resp.code.to_s == "200" || resp.code.to_s == "201"
    merge_attributes(JSON.parse(resp))
    return true
  else
    error_response = JSON.parse(resp)
    if error_response["error"]
      pe = ParseError.new(error_response["code"], error_response["error"])
    else
      pe = ParseError.new(resp.code.to_s)
    end
    self.errors.add(pe.code.to_s.to_sym, pe.msg)
    self.error_instances << pe     
    return false
  end      
end
reload() click to toggle source
# File lib/parse_resource/base.rb, line 473
def reload
  return false if new?
  
  fresh_object = self.class.find(id)
  @attributes.update(fresh_object.instance_variable_get('@attributes'))
  @unsaved_attributes = {}
  
  self
end
resource() click to toggle source

delegate from Class method

# File lib/parse_resource/base.rb, line 365
def resource
  self.class.resource
end
save() click to toggle source
# File lib/parse_resource/base.rb, line 389
def save
  if valid?
    run_callbacks :save do
      if new?
        return create 
      else
        return update
      end
    end
  else
    false
  end
  rescue false
end
set_attribute(k, v) click to toggle source
# File lib/parse_resource/base.rb, line 527
def set_attribute(k, v)
  if v.is_a?(Date) || v.is_a?(Time) || v.is_a?(DateTime)
    v = self.class.to_date_object(v)
  elsif v.respond_to?(:to_pointer)
    v = v.to_pointer 
  end
  @unsaved_attributes[k.to_s] = v unless v == @attributes[k.to_s] # || @unsaved_attributes[k.to_s]
  @attributes[k.to_s] = v
  v
end
to_pointer() click to toggle source
# File lib/parse_resource/base.rb, line 92
def to_pointer
  klass_name = self.class.model_name
  klass_name = "_User" if klass_name == "User"
  klass_name = "_Installation" if klass_name == "Installation"
  {"__type" => "Pointer", "className" => klass_name.to_s, "objectId" => self.id}
end
update(attributes = {}) click to toggle source
# File lib/parse_resource/base.rb, line 412
def update(attributes = {})
  
  attributes = HashWithIndifferentAccess.new(attributes)
    
  @unsaved_attributes.merge!(attributes)
  put_attrs = attributes_for_saving.to_json
  
  opts = {:content_type => "application/json"}
  result = self.instance_resource.put(put_attrs, opts) do |resp, req, res, &block|
    return post_result(resp, req, res, &block)
  end
end
update_attributes(attributes = {}) click to toggle source
# File lib/parse_resource/base.rb, line 460
def update_attributes(attributes = {})
  self.update(attributes)
end
updated_at() click to toggle source
# File lib/parse_resource/base.rb, line 545
def updated_at; get_attribute("updatedAt"); rescue nil; end