{"id":18728772,"url":"https://github.com/rubyonworld/parse-stack","last_synced_at":"2025-07-30T19:42:24.872Z","repository":{"id":174008024,"uuid":"542158959","full_name":"RubyOnWorld/parse-stack","owner":"RubyOnWorld","description":"A full featured Active Model ORM and Ruby REST API for Parse-Server. Parse Stack is the Parse Server SDK, REST Client and ORM framework for Ruby.","archived":false,"fork":false,"pushed_at":"2022-09-28T01:11:00.000Z","size":1188,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-05-19T20:32:51.006Z","etag":null,"topics":["model","orm","rails","rest","ruby"],"latest_commit_sha":null,"homepage":"","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/RubyOnWorld.png","metadata":{"files":{"readme":"README.md","changelog":"Changes.md","contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-09-27T15:31:12.000Z","updated_at":"2022-09-28T04:13:43.000Z","dependencies_parsed_at":null,"dependency_job_id":"a865296c-c089-4f49-9321-40b652a85d79","html_url":"https://github.com/RubyOnWorld/parse-stack","commit_stats":null,"previous_names":["rubyonworld/parse-stack"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/RubyOnWorld/parse-stack","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RubyOnWorld%2Fparse-stack","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RubyOnWorld%2Fparse-stack/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RubyOnWorld%2Fparse-stack/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RubyOnWorld%2Fparse-stack/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/RubyOnWorld","download_url":"https://codeload.github.com/RubyOnWorld/parse-stack/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RubyOnWorld%2Fparse-stack/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":267929324,"owners_count":24167449,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-07-30T02:00:09.044Z","response_time":70,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["model","orm","rails","rest","ruby"],"created_at":"2024-11-07T14:24:18.505Z","updated_at":"2025-07-30T19:42:24.774Z","avatar_url":"https://github.com/RubyOnWorld.png","language":"Ruby","readme":"![Parse Stack - The Parse Server Ruby Client SDK](https://raw.githubusercontent.com/modernistik/parse-stack/master/parse-stack.png?raw=true)\n\nA full featured Active Model ORM and Ruby REST API for Parse-Server. [Parse Stack](https://github.com/modernistik/parse-stack) is the [Parse Server](http://parseplatform.org/) SDK, REST Client and ORM framework for [Ruby](https://www.ruby-lang.org/en/). It provides a client adapter, a query engine, an object relational mapper (ORM) and a Cloud Code Webhooks rack application.\n\nBelow is a [quick start guide](https://github.com/modernistik/parse-stack#overview), but you can also check out the full *[API Reference](https://www.modernistik.com/gems/parse-stack/index.html)* for more detailed information about our Parse Server SDK.\n\n### Hire Us\n\nInterested in our work? You can find us here: [https://www.modernistik.com](https://www.modernistik.com)\n\n### Code Status\n[![Gem Version](https://img.shields.io/gem/v/parse-stack.svg)](https://github.com/modernistik/parse-stack)\n[![Downloads](https://img.shields.io/gem/dt/parse-stack.svg)](https://rubygems.org/gems/parse-stack)\n[![Build Status](https://travis-ci.org/modernistik/parse-stack.svg?branch=master)](https://travis-ci.org/modernistik/parse-stack)\n[![API Reference](http://img.shields.io/badge/api-docs-blue.svg)](https://www.modernistik.com/gems/parse-stack/index.html)\n\n#### Tutorial Videos\n1. Getting Started: https://youtu.be/zoYSGmciDlQ\n2. Custom Classes and Relations: https://youtu.be/tfSesotfU7w\n3. Working with Existing Schemas: https://youtu.be/EJGPT7YWyXA\n\nAny other questions, please post them on StackOverflow with the proper parse-stack / parse-server / ruby tags.\n\n## Installation\n\nAdd this line to your application's `Gemfile`:\n```ruby\ngem 'parse-stack'\n```\nAnd then execute:\n```bash\n$ bundle\n```\nOr install it yourself as:\n```bash\n$ gem install parse-stack\n```\n### Rack / Sinatra\nParse-Stack API, models and webhooks easily integrate in your existing Rack/Sinatra based applications. For more details see [Parse-Stack Rack Example](https://github.com/modernistik/parse-stack-example).\n\n### Rails\nParse-Stack comes with support for Rails by adding additional rake tasks and generators. After adding `parse-stack` as a gem dependency in your Gemfile and running `bundle`, you should run the install script:\n```bash\n$ rails g parse_stack:install\n```\nFor a more details on the rails integration see [Parse-Stack Rails Example](https://github.com/modernistik/parse-stack-rails-example).\n\n### Interactive Command Line Playground\nYou can also used the bundled `parse-console` command line to connect and interact with your Parse Server and its data in an IRB-like console. This is useful for trying concepts and debugging as it will automatically connect to your Parse Server, and if provided the master key, automatically generate all the models entities.\n\n```bash\n$ parse-console -h # see all options\n$ parse-console -v -a myAppId -m myMasterKey http://localhost:1337/parse\nServer : http://localhost:1337/parse\nApp Id : myAppId\nMaster : true\n2.4.0 \u003e Parse::User.first\n```\n\n## Overview\nParse-Stack is a full stack framework that utilizes several ideas behind [DataMapper](http://datamapper.org/docs/find.html) and [ActiveModel](https://github.com/rails/rails/tree/master/activemodel) to manage and maintain larger scale ruby applications and tools that utilize the [Parse Server Platform](http://parseplatform.org/). If you are familiar with these technologies, the framework should feel familiar to you.\n\n```ruby\nrequire 'parse/stack'\n\nParse.setup server_url: 'http://localhost:1337/parse',\n            app_id: APP_ID,\n            api_key: REST_API_KEY,\n            master_key: YOUR_MASTER_KEY # optional\n\n# Automatically build models based on your Parse application schemas.\nParse.auto_generate_models!\n\n# or define custom Subclasses (Highly Recommended)\nclass Song \u003c Parse::Object\n  property :name\n  property :play, :integer\n  property :audio_file, :file\n  property :tags, :array\n  property :released, :date\n  belongs_to :artist\n  # `like` is a Parse Relation to User class\n  has_many :likes, as: :user, through: :relation\n\n  # deny public write to Song records by default\n  set_default_acl :public, read: true, write: false\nend\n\nclass Artist \u003c Parse::Object\n  property :name\n  property :genres, :array\n  has_many :fans, as: :user\n  has_one :manager, as: :user\n\n  scope :recent, -\u003e(x) { query(:created_at.after =\u003e x) }\nend\n\n# updates schemas for your Parse app based on your models (non-destructive)\nParse.auto_upgrade!\n\n# login\nuser = Parse::User.login(username, passwd)\n\nartist = Artist.new(name: \"Frank Sinatra\", genres: [\"swing\", \"jazz\"])\nartist.fans \u003c\u003c user\nartist.save\n\n# Query\nartist = Artist.first(:name.like =\u003e /Sinatra/, :genres.in =\u003e ['swing'])\n\n# more examples\nsong = Song.new name: \"Fly Me to the Moon\"\nsong.artist = artist\n# Parse files - upload a file and attach to object\nsong.audio_file = Parse::File.create(\"http://path_to.mp3\")\n\n# relations - find a User matching username and add it to relation.\nsong.likes.add Parse::User.first(username: \"persaud\")\n\n# saves both attributes and relations\nsong.save\n\n# find songs\nsongs = Song.all(artist: artist, :plays.gt =\u003e 100, :released.on_or_after =\u003e 30.days.ago)\n\nsongs.each { |s| s.tags.add \"awesome\" }\n# batch saves\nsongs.save\n\n# Call Cloud Code functions\nresult = Parse.call_function :myFunctionName, {param: value}\n\n```\n## Table of Contents\n\n\u003c!-- START doctoc generated TOC please keep comment here to allow auto update --\u003e\n\u003c!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE --\u003e\n\n\n- [Architecture](#architecture)\n  - [Parse::Client](#parseclient)\n  - [Parse::Query](#parsequery)\n  - [Parse::Object](#parseobject)\n  - [Parse::Webhooks](#parsewebhooks)\n- [Field Naming Conventions](#field-naming-conventions)\n- [Connection Setup](#connection-setup)\n  - [Connection Options](#connection-options)\n- [Working With Existing Schemas](#working-with-existing-schemas)\n- [Parse Config](#parse-config)\n- [Core Classes](#core-classes)\n  - [Parse::Pointer](#parsepointer)\n  - [Parse::File](#parsefile)\n  - [Parse::Date](#parsedate)\n  - [Parse::GeoPoint](#parsegeopoint)\n    - [Calculating Distances between locations](#calculating-distances-between-locations)\n  - [Parse::Bytes](#parsebytes)\n  - [Parse::TimeZone](#parsetimezone)\n  - [Parse::ACL](#parseacl)\n  - [Parse::Session](#parsesession)\n  - [Parse::Installation](#parseinstallation)\n  - [Parse::Product](#parseproduct)\n  - [Parse::Role](#parserole)\n  - [Parse::User](#parseuser)\n    - [Signup](#signup)\n      - [Third-Party Services](#third-party-services)\n    - [Login and Sessions](#login-and-sessions)\n    - [Linking and Unlinking](#linking-and-unlinking)\n    - [Request Password Reset](#request-password-reset)\n- [Modeling and Subclassing](#modeling-and-subclassing)\n  - [Defining Properties](#defining-properties)\n    - [Accessor Aliasing](#accessor-aliasing)\n    - [Property Options](#property-options)\n      - [`:required`](#required)\n      - [`:field`](#field)\n      - [`:default`](#default)\n      - [`:alias`](#alias)\n      - [`:symbolize`](#symbolize)\n      - [`:enum`](#enum)\n      - [`:scope`](#scope)\n  - [Associations](#associations)\n    - [Belongs To](#belongs-to)\n      - [Options](#options)\n        - [`:required`](#required-1)\n        - [`:as`](#as)\n        - [`:field`](#field-1)\n    - [Has One](#has-one)\n    - [Has Many](#has-many)\n      - [Query](#query)\n      - [Array](#array)\n      - [Parse Relation](#parse-relation)\n      - [Options](#options-1)\n        - [`:through`](#through)\n        - [`:scope_only`](#scope_only)\n- [Creating, Saving and Deleting Records](#creating-saving-and-deleting-records)\n  - [Create](#create)\n  - [Saving](#saving)\n  - [Saving applying User ACLs](#saving-applying-user-acls)\n    - [Raising an exception when save fails](#raising-an-exception-when-save-fails)\n  - [Modifying Associations](#modifying-associations)\n  - [Batch Requests](#batch-requests)\n  - [Magic `save_all`](#magic-save_all)\n  - [Deleting](#deleting)\n- [Fetching, Finding and Counting Records](#fetching-finding-and-counting-records)\n  - [Auto-Fetching Associations](#auto-fetching-associations)\n- [Advanced Querying](#advanced-querying)\n  - [Results Caching](#results-caching)\n  - [Counting](#counting)\n  - [Distinct Aggregation](#distinct-aggregation)\n  - [Query Expressions](#query-expressions)\n    - [:order](#order)\n    - [:keys](#keys)\n    - [:includes](#includes)\n    - [:limit](#limit)\n    - [:skip](#skip)\n    - [:cache](#cache)\n    - [:use_master_key](#use_master_key)\n    - [:session](#session)\n    - [:where](#where)\n- [Query Constraints](#query-constraints)\n    - [Equals](#equals)\n    - [Less Than](#less-than)\n    - [Less Than or Equal To](#less-than-or-equal-to)\n    - [Greater Than](#greater-than)\n    - [Greater Than or Equal](#greater-than-or-equal)\n    - [Not Equal To](#not-equal-to)\n    - [Nullability Check](#nullability-check)\n    - [Exists](#exists)\n    - [Contained In](#contained-in)\n    - [Not Contained In](#not-contained-in)\n    - [Contains All](#contains-all)\n    - [Regex Matching](#regex-matching)\n    - [Select](#select)\n    - [Reject](#reject)\n    - [Matches Query](#matches-query)\n    - [Excludes Query](#excludes-query)\n    - [Matches Object Id](#matches-object-id)\n  - [Geo Queries](#geo-queries)\n    - [Max Distance Constraint](#max-distance-constraint)\n    - [Bounding Box Constraint](#bounding-box-constraint)\n    - [Polygon Area Constraint](#polygon-area-constraint)\n    - [Full Text Search Constraint](#full-text-search-constraint)\n  - [Relational Queries](#relational-queries)\n  - [Compound Queries](#compound-queries)\n- [Query Scopes](#query-scopes)\n- [Calling Cloud Code Functions](#calling-cloud-code-functions)\n- [Calling Background Jobs](#calling-background-jobs)\n- [Active Model Callbacks](#active-model-callbacks)\n- [Schema Upgrades and Migrations](#schema-upgrades-and-migrations)\n- [Push Notifications](#push-notifications)\n- [Cloud Code Webhooks](#cloud-code-webhooks)\n  - [Cloud Code Functions](#cloud-code-functions)\n  - [Cloud Code Triggers](#cloud-code-triggers)\n  - [Mounting Webhooks Application](#mounting-webhooks-application)\n  - [Register Webhooks](#register-webhooks)\n- [Parse REST API Client](#parse-rest-api-client)\n  - [Request Caching](#request-caching)\n- [Contributing](#contributing)\n- [License](#license)\n\n\u003c!-- END doctoc generated TOC please keep comment here to allow auto update --\u003e\n\n## Architecture\nThe architecture of `Parse::Stack` is broken into four main components.\n\n### [Parse::Client](https://www.modernistik.com/gems/parse-stack/Parse/Client.html)\nThis class is the core and low level API for the Parse Server REST interface that is used by the other components. It can manage multiple sessions, which means you can have multiple client instances pointing to different Parse Server applications at the same time. It handles sending raw requests as well as providing Request/Response objects for all API handlers. The connection engine is Faraday, which means it is open to add any additional middleware for features you'd like to implement.\n\n### [Parse::Query](https://www.modernistik.com/gems/parse-stack/Parse/Query.html)\nThis class implements the [Parse REST Querying](http://docs.parseplatform.org/rest/guide/#queries) interface in the [DataMapper finder syntax style](http://datamapper.org/docs/find.html). It compiles a set of query constraints and utilizes `Parse::Client` to send the request and provide the raw results. This class can be used without the need to define models.\n\n### [Parse::Object](https://www.modernistik.com/gems/parse-stack/Parse/Object.html)\nThis component is main class for all object relational mapping subclasses for your application. It provides features in order to map your remote Parse records to a local ruby object. It implements the Active::Model interface to provide a lot of additional features, CRUD operations, querying, including dirty tracking, JSON serialization, save/destroy callbacks and others. While we are overlooking some functionality, for simplicity, you will mainly be working with Parse::Object as your superclass. While not required, it is highly recommended that you define a model (Parse::Object subclass) for all the Parse classes in your application.\n\n### [Parse::Webhooks](https://www.modernistik.com/gems/parse-stack/Parse/Webhooks.html)\nParse provides a feature called [Cloud Code Webhooks](http://blog.parse.com/announcements/introducing-cloud-code-webhooks/). For most applications, save/delete triggers and cloud functions tend to be implemented by Parse's own hosted Javascript solution called Cloud Code. However, Parse provides the ability to have these hooks utilize your hosted solution instead of their own, since their environment is limited in terms of resources and tools.\n\n## Field Naming Conventions\nBy convention in Ruby (see [Style Guide](https://github.com/bbatsov/ruby-style-guide#snake-case-symbols-methods-vars)), symbols and variables are expressed in lower_snake_case form. Parse, however, prefers column names in **lower-first camel case** (ex. `objectId`, `createdAt` and `updatedAt`). To keep in line with the style guides between the languages, we do the automatic conversion of the field names when compiling the query. As an additional exception to this rule, the field key of `id` will automatically be converted to the `objectId` field when used. If you do not want this to happen, you can turn off or change the value `Parse::Query.field_formatter` as shown below. Though we recommend leaving the default `:columnize` if possible.\n\n```ruby\n# default uses :columnize\nquery = Parse::User.query :field_one =\u003e 1, :FieldTwo =\u003e 2, :Field_Three =\u003e 3\nquery.compile_where # {\"fieldOne\"=\u003e1, \"fieldTwo\"=\u003e2, \"fieldThree\"=\u003e3}\n\n# turn off\nParse::Query.field_formatter = nil\nquery = Parse::User.query :field_one =\u003e 1, :FieldTwo =\u003e 2, :Field_Three =\u003e 3\nquery.compile_where # {\"field_one\"=\u003e1, \"FieldTwo\"=\u003e2, \"Field_Three\"=\u003e3}\n\n# force everything camel case\nParse::Query.field_formatter = :camelize\nquery = Parse::User.query :field_one =\u003e 1, :FieldTwo =\u003e 2, :Field_Three =\u003e 3\nquery.compile_where # {\"FieldOne\"=\u003e1, \"FieldTwo\"=\u003e2, \"FieldThree\"=\u003e3}\n\n```\n\n\n## Connection Setup\nTo connect to a Parse server, you will need a minimum of an `application_id`, an `api_key` and a `server_url`. To connect to the server endpoint, you use the `Parse.setup()` method below.\n\n```ruby\n  Parse.setup app_id: \"YOUR_APP_ID\",\n              api_key: \"YOUR_API_KEY\",\n              master_key: \"YOUR_MASTER_KEY\", # optional\n              server_url: 'https://localhost:1337/parse' #default\n```\n\nIf you wish to add additional connection middleware to the stack, you may do so by utilizing passing a block to the setup method.\n\n```ruby\n  Parse.setup( ... ) do |conn|\n    # conn is a Faraday connection object\n    conn.use Your::Middleware\n    conn.response :logger\n    # ....\n  end\n```\n\nCalling `setup` will create the default `Parse::Client` session object that will be used for all models and requests in the stack. You may retrive this client by calling the class `client` method. It is possible to create different client connections and have different models point to different Parse applications and endpoints at the same time.\n\n```ruby\n  default_client = Parse.client\n                   # alias Parse::Client.client(:default)\n```\n\n### Connection Options\nThere are additional connection options that you may pass the setup method when creating a `Parse::Client`.\n\n#### `:server_url`\nThe server url of your Parse Server if you are not using the hosted Parse service. By default it will use `PARSE_SERVER_URL` environment variable available or fall back to `https://localhost:1337/parse` if not specified.\n\n#### `:app_id`\nThe Parse application id. By default it will use `PARSE_SERVER_APPLICATION_ID` environment variable if not specified.\n\n#### `:api_key`\nThe Parse REST API Key. By default it will use `PARSE_SERVER_REST_API_KEY` environment variable if not specified.\n\n#### `:master_key` _(optional)_\nThe Parse application master key. If this key is set, it will be sent on every request sent by the client and your models. By default it will use `PARSE_SERVER_MASTER_KEY` environment variable if not specified.\n\n#### `:logging`\nA true or false value. It provides you additional logging information of requests and responses. If set to the special symbol of `:debug`, it will provide additional payload data in the log messages.\n\n#### `:adapter`\nThe connection adapter. By default it uses the `Faraday.default_adapter` which is Net/HTTP.\n\n#### `:cache`\nA caching adapter of type `Moneta::Transformer`. Caching queries and object fetches can help improve the performance of your application, even if it is for a few seconds. Only successful `GET` object fetches and queries (non-empty) will be cached. You may set the default expiration time with the `expires` option. See related: [Moneta](https://github.com/minad/moneta). At any point in time you may clear the cache by calling the `clear_cache!` method on the client connection.\n\n```ruby\n  store = Moneta.new :Redis, url: 'redis://localhost:6379'\n   # use a Redis cache store with an automatic expire of 10 seconds.\n  Parse.setup(cache: store, expires: 10, ...)\n```\n\nAs a shortcut, if you are planning on using REDIS and have configured the use of `redis` in your `Gemfile`, you can just pass the REDIS connection string directly to the cache option.\n\n```ruby\n  Parse.setup(cache: 'redis://localhost:6379', ...)\n```\n\n#### `:expires`\nSets the default cache expiration time (in seconds) for successful non-empty `GET` requests when using the caching middleware. The default value is 3 seconds. If `:expires` is set to 0, caching will be disabled. You can always clear the current state of the cache using the `clear_cache!` method on your `Parse::Client` instance.\n\n#### `:faraday`\nYou may pass a hash of options that will be passed to the `Faraday` constructor.\n\n## Working With Existing Schemas\nIf you already have a Parse application with defined schemas and collections, you can have Parse-Stack automatically generate the ruby Parse::Object subclasses instead of writing them on your own. Through this process, the framework will download all the defined schemas of all your collections, and infer the properties and associations defined. While this method is useful for getting started with the framework with an existing app, we highly recommend defining your own models. This would allow you to customize and utilize all the features available in Parse Stack.\n\n```ruby\n  # after you have called Parse.setup\n  # Assume you have a Song and Artist collections defined remotely\n  Parse.auto_generate_models!\n\n  # You can now use them as if you defined them\n  artist = Artist.first\n  Song.all(artist: artist)\n```\n\nYou can always combine both approaches by defining special attributes before you auto generate your models:\n\n```ruby\n  # create a Song class, but only create the artist array pointer association.\n  class Song \u003c Parse::Object\n    has_many :artists, through: :array\n  end\n\n  # Now let Parse Stack generate the rest of the properties and associations\n  # based on your remote schema. Assume there is a `title` field for the `Song`\n  # collection.\n  Parse.auto_generate_models!\n\n  song = Song.first\n  song.artists # created with our definition above\n  song.title # auto-generated property\n\n```\n\n## [Parse Config](https://www.modernistik.com/gems/parse-stack/Parse/API/Config.html)\nGetting your configuration variables once you have a default client setup can be done with `Parse.config`. The first time this method is called, Parse-Stack will get the configuration from Parse Server, and cache it. To force a reload of the config, use `config!`. You\n\n```ruby\n  Parse.setup( ... )\n\n  val = Parse.config[\"myKey\"]\n  val = Parse.config[\"myKey\"] # cached\n\n  # update a config with Parse\n  Parse.set_config \"myKey\", \"someValue\"\n\n  # batch update several\n  Parse.update_config({fieldEnabled: true, searchMiles: 50})\n\n  # Force fetch of config!\n  val = Parse.config![\"myKey\"]\n\n```\n\n## Core Classes\nWhile some native data types are similar to the ones supported by Ruby natively, other ones are more complex and require their dedicated classes.\n\n### [Parse::Pointer](https://www.modernistik.com/gems/parse-stack/Parse/Pointer.html)\nAn important concept is the `Parse::Pointer` class. This is the superclass of `Parse::Object` and represents the pointer type in Parse. A `Parse::Pointer` only contains data about the specific Parse class and the `id` for the object. Therefore, creating an instance of any Parse::Object subclass with only the `:id` field set will be considered in \"pointer\" state even though its specific class is not `Parse::Pointer` type. The only case that you may have a Parse::Pointer is in the case where an object was received for one of your classes and the framework has no registered class handler for it. Using the example above, assume you have the tables `Post`, `Comment` and `Author` defined in your remote Parse application, but have only defined `Post` and `Commentary` locally.\n\n```ruby\n # assume the following\nclass Post \u003c Parse::Object\nend\n\nclass Commentary \u003c Parse::Object\n  parse_class \"Comment\"\n\tbelongs_to :post\n\t#'Author' class not defined locally\n\tbelongs_to :author\nend\n\ncomment = Commentary.first\ncomment.post? # true because it is non-nil\ncomment.artist? # true because it is non-nil\n\n# both are true because they are in a Pointer state\ncomment.post.pointer? # true\ncomment.author.pointer? # true\n\n # we have defined a Post class handler\ncomment.post # \u003cPost @parse_class=\"Post\", @id=\"xdqcCqfngz\"\u003e\n\n # we have not defined an Author class handler\ncomment.author # \u003cParse::Pointer @parse_class=\"Author\", @id=\"hZLbW6ofKC\"\u003e\n\n\ncomment.post.fetch # fetch the relation\ncomment.post.pointer? # false, it is now a full object.\n```\n\nThe effect is that for any unknown classes that the framework encounters, it will generate Parse::Pointer instances until you define those classes with valid properties and associations. While this might be ok for some classes you do not use, we still recommend defining all your Parse classes locally in the framework.\n\n### [Parse::File](https://www.modernistik.com/gems/parse-stack/Parse/File.html)\nThis class represents a Parse file pointer. `Parse::File` has helper methods to upload Parse files directly to Parse and manage file associations with your classes. Using our Song class example:\n\n```ruby\n  song = Song.first\n  file = song.audio_file # Parse::File\n  file.url # URL in the Parse file storage system\n\n  file = File.open(\"file_path.jpg\")\n  contents = file.read\n  file = Parse::File.new(\"myimage.jpg\", contents , \"image/jpeg\")\n  file.saved? # false. Hasn't been uploaded to Parse\n  file.save # uploads to Parse.\n\n  file.url # https://files.parsetfss.com/....\n\n  # or create and upload a remote file (auto-detected mime type)\n  file = Parse::File.create(some_url)\n  song.file = file\n  song.save\n\n```\n\nThe default MIME type for all files is `image/jpeg`. This can be default can be changed by setting a value to `Parse::File.default_mime_type`. Other ways of creating a `Parse::File` are provided below. The created Parse::File is not uploaded until you call `save`.\n\n```ruby\n  # urls\n  file = Parse::File.new \"http://example.com/image.jpg\"\n  file.name # image.jpg\n\n  # file objects\n  file = Parse::File.new File.open(\"myimage.jpg\")\n\n  # non-image files work too\n  file = Parse::File.new \"http://www.example.com/something.pdf\"\n  file.mime_type = \"application/octet-stream\" #set the mime-type!\n\n  # or another Parse::File object\n  file = Parse::File.new parse_file\n```\n\nIf you are using displaying these files on a secure site and want to make sure that urls returned by a call to `url` are `https`, you can set `Parse::File.force_ssl` to true.\n\n```ruby\n# Assume file is a Parse::File\n\nfile.url # =\u003e http://www.example.com/file.png\n\nParse::File.force_ssl = true # make all urls be https\n\nfile.url # =\u003e https://www.example.com/file.png\n\n```\n\n### [Parse::Date](https://www.modernistik.com/gems/parse-stack/Parse/Date.html)\nThis class manages dates in the special JSON format it requires for properties of type `:date`. `Parse::Date` subclasses `DateTime`, which allows you to use any features or methods available to `DateTime` with `Parse::Date`. While the conversion between `Time` and `DateTime` objects to a `Parse::Date` object is done implicitly for you, you can use the added special methods, `DateTime#parse_date` and `Time#parse_date`, for special occasions.\n\n```ruby\n  song = Song.first\n  song.released = DateTime.now # converted to Parse::Date\n  song.save # ok\n```\n\n### [Parse::GeoPoint](https://www.modernistik.com/gems/parse-stack/Parse/GeoPoint.html)\nThis class manages the GeoPoint data type that Parse provides to support geo-queries. To define a GeoPoint property, use the `:geopoint` data type. Please note that latitudes should not be between -90.0 and 90.0, and longitudes should be between -180.0 and 180.0.\n\n```ruby\n  class PlaceObject \u003c Parse::Object\n    property :location, :geopoint\n  end\n\n  san_diego = Parse::GeoPoint.new(32.8233, -117.6542)\n  los_angeles = Parse::GeoPoint.new [34.0192341, -118.970792]\n  san_diego == los_angeles # false\n\n  place = PlaceObject.new\n  place.location = san_diego\n  place.save\n```\n\n#### Calculating Distances between locations\nWe include helper methods to calculate distances between GeoPoints: `distance_in_miles` and `distance_in_km`.\n\n```ruby\n\tsan_diego = Parse::GeoPoint.new(32.8233, -117.6542)\n\tlos_angeles = Parse::GeoPoint.new [34.0192341, -118.970792]\n\n\t# Haversine calculations\n\tsan_diego.distance_in_miles(los_angeles)\n\t# ~112.33 miles\n\n\tsan_diego.distance_in_km(los_angeles)\n\t# ~180.793 km\n```\n\n### [Parse::Bytes](https://www.modernistik.com/gems/parse-stack/Parse/Bytes.html)\nThe `Bytes` data type represents the storage format for binary content in a Parse column. The content is needs to be encoded into a base64 string.\n\n```ruby\n  bytes = Parse::Bytes.new( base64_string )\n  # or use helper method\n  bytes = Parse::Bytes.new\n  bytes.encode( content ) # same as Base64.encode64\n\n  decoded = bytes.decoded # same as Base64.decode64\n```\n\n### [Parse::TimeZone](https://www.modernistik.com/gems/parse-stack/Parse/TimeZone.html)\nWhile Parse does not provide a native time zone data type, Parse-Stack provides a class to make it easier to manage time zone attributes, usually stored IANA string identifiers, with your ruby code. This is done by utilizing the features provided by [`ActiveSupport::TimeZone`](http://api.rubyonrails.org/classes/ActiveSupport/TimeZone.html). In addition to setting a column as a time zone field, we also add special validations to verify it is of the right IANA identifier.\n\n```ruby\nclass Event \u003c Parse::Object\n  # an event occurs in a time zone.\n  property :time_zone, :timezone, default: 'America/Los_Angeles'\nend\n\nevent = Event.new\nevent.time_zone.name # =\u003e 'America/Los_Angeles'\nevent.time_zone.valid? # =\u003e true\n\nevent.time_zone.zone # =\u003e ActiveSupport::TimeZone\nevent.time_zone.formatted_offset # =\u003e \"-08:00\"\n\nevent.time_zone = 'Europe/Paris'\nevent.time_zone.formatted_offset # =\u003e +01:00\"\n\nevent.time_zone = 'Galaxy/Andromeda'\nevent.time_zone.valid? # =\u003e false\n```\n\n### [Parse::ACL](https://www.modernistik.com/gems/parse-stack/Parse/ACL.html)\nThe `ACL` class represents the access control lists for each record. An ACL is represented by a JSON object with the keys being `Parse::User` object ids or the special key of `*`, which indicates the public access permissions.\nThe value of each key in the hash is a [`Parse::ACL::Permission`](https://www.modernistik.com/gems/parse-stack/Parse/ACL/Permission.html) object which defines the boolean permission state for `read` and `write`.\n\nThe example below illustrates a Parse ACL JSON object where there is a public read permission, but public write is prevented. In addition, the user with id `3KmCvT7Zsb` and the `Admins` role, are allowed to both read and write on this record.\n\n```json\n{\n  \"*\": { \"read\": true },\n  \"3KmCvT7Zsb\": {  \"read\": true, \"write\": true },\n  \"role:Admins\": {  \"read\": true, \"write\": true }\n}\n```\n\nAll `Parse::Object` subclasses have an `acl` property by default. With this property, you can apply and delete permissions for this particular Parse object record.\n\n```ruby\n  user = Parse::User.first\n  artist = Artist.first\n\n  artist.acl # \"*\": { \"read\": true, \"write\": true }\n\n  # apply public read, but no public write\n  artist.acl.everyone true, false\n\n  # allow user to have read and write access\n  artist.acl.apply user.id, true, true\n\n  # remove all permissions for this user id\n  artist.acl.delete user.id\n\n  # allow the 'Admins' role read and write\n  artist.acl.apply_role \"Admins\", true, true\n\n  # remove write from all attached privileges\n  artist.acl.no_write!\n\n  # remove all attached privileges\n  artist.acl.master_key_only!\n\n  artist.save\n```\nYou may also set default ACLs for newly created instances of your subclasses using `set_default_acl`:\n\n```ruby\nclass AdminData \u003c Parse::Object\n\n  # Disable public read and write\n  set_default_acl :public, read: false, write: false\n\n  # but allow members of the Admin role to read and write\n  set_default_acl 'Admin', role: true, read: true, write: true\n\nend\n\ndata = AdminData.new\ndata.acl # =\u003e ACL({\"role:Admin\"=\u003e{\"read\"=\u003etrue, \"write\"=\u003etrue}})\n```\n\nFor more information about Parse record ACLs, see the documentation at  [Security](http://docs.parseplatform.org/rest/guide/#security)\n\n### [Parse::Session](https://www.modernistik.com/gems/parse-stack/Parse/Session.html)\nThis class represents the data and columns contained in the standard Parse `_Session` collection. You may add additional properties and methods to this class. See [Session API Reference](https://www.modernistik.com/gems/parse-stack/Parse/Session.html). You may call `Parse.use_shortnames!` to use `Session` in addition to `Parse::Session`.\n\nYou can get a specific `Parse::Session` given a session_token by using the `session` method. You can also find the user tied to a specific Parse session or session token with `Parse::User.session`.\n\n```ruby\nsession = Parse::Session.session(token)\n\nsession.user # the Parse user for this session\n\n# or fetch user with a session token\nuser = Parse::User.session(token)\n\n# save an object with the privileges (ACLs) of this user\nsome_object.save( session: user.session_token )\n\n# delete an object with the privileges of this user\nsome_object.destroy( session: user.session_token )\n\n```\n\n### [Parse::Installation](https://www.modernistik.com/gems/parse-stack/Parse/Installation.html)\nThis class represents the data and columns contained in the standard Parse `_Installation` collection. You may add additional properties and methods to this class. See [Installation API Reference](https://www.modernistik.com/gems/parse-stack/Parse/Installation.html). You may call `Parse.use_shortnames!` to use `Installation` in addition to `Parse::Installation`.\n\n### [Parse::Product](https://www.modernistik.com/gems/parse-stack/Parse/Product.html)\nThis class represents the data and columns contained in the standard Parse `_Product` collection. You may add additional properties and methods to this class. See [Product API Reference](https://www.modernistik.com/gems/parse-stack/Parse/Product.html). You may call `Parse.use_shortnames!` to use `Product` in addition to `Parse::Product`.\n\n### [Parse::Role](https://www.modernistik.com/gems/parse-stack/Parse/Role.html)\nThis class represents the data and columns contained in the standard Parse `_Role` collection. You may add additional properties and methods to this class. See [Roles API Reference](https://www.modernistik.com/gems/parse-stack/Parse/Role.html). You may call `Parse.use_shortnames!` to use `Role` in addition to `Parse::Role`.\n\n### [Parse::User](https://www.modernistik.com/gems/parse-stack/Parse/User.html)\nThis class represents the data and columns contained in the standard Parse `_User` collection. You may add additional properties and methods to this class. See [User API Reference](https://www.modernistik.com/gems/parse-stack/Parse/User.html). You may call `Parse.use_shortnames!` to use `User` in addition to `Parse::User`.\n\n#### Signup\nYou can signup new users in two ways. You can either use a class method `Parse::User.signup` to create a new user with the minimum fields of username, password and email, or create a `Parse::User` object can call the `signup!` method. If signup fails, it will raise the corresponding exception.\n\n```ruby\nuser = Parse::User.signup(username, password, email)\n\n#or\nuser = Parse::User.new username: \"user\", password: \"s3cret\"\nuser.signup!\n```\n\n##### Third-Party Services\nYou can signup users using third-party services like Facebook and Twitter as described in: [Signing Up and Logging In](http://docs.parseplatform.org/rest/guide/#signing-up). To do this with Parse-Stack, you can call the `Parse::User.autologin_service` method by passing the service name and the corresponding authentication hash data. For a listing of supported third-party authentication services, see [OAuth](http://docs.parseplatform.org/parse-server/guide/#oauth-and-3rd-party-authentication).\n\n```ruby\nfb_auth = {}\nfb_auth[:id] = \"123456789\"\nfb_auth[:access_token] = \"SaMpLeAAiZBLR995wxBvSGNoTrEaL\"\nfb_auth[:expiration_date] = \"2025-02-21T23:49:36.353Z\"\n\n# signup or login a user with this auth data.\nuser = Parse::User.autologin_service(:facebook, fb_auth)\n```\n\nYou may also combine both approaches of signing up a new user with a third-party service and set additional custom fields. For this, use the method `Parse::User.create`.\n\n```ruby\n# or to signup a user with additional data, but linked to Facebook\ndata = {\n  username: \"johnsmith\",\n  name: \"John\",\n  email: \"user@example.com\",\n  authData: { facebook: fb_auth }\n}\nuser = Parse::User.create data\n```\n\n#### Login and Sessions\nWith the `Parse::User` class, you can also perform login and logout functionality. The class special accessors for `session_token` and `session` to manage its authentication state. This will allow you to authenticate users as well as perform Parse queries as a specific user using their session token. To login a user, use the `Parse::User.login` method by supplying the corresponding username and password, or if you already have a user record, use `login!` with the proper password.\n\n```ruby\nuser = Parse::User.login(username,password)\nuser.session_token # session token from a Parse::Session\nuser.session # Parse::Session tied to the token\n\n # You can login user records\nuser = Parse::User.first\nuser.session_token # nil\n\npasswd = 'p_n7!-e8' # corresponding password\nuser.login!(passwd) # true\n\nuser.session_token # 'r:pnktnjyb996sj4p156gjtp4im'\n\n # logout to delete the session\nuser.logout\n```\n\nIf you happen to already have a valid session token, you can use it to retrieve the corresponding Parse::User.\n\n```ruby\n# finds user with session token\nuser = Parse::User.session(session_token)\n\nuser.logout # deletes the corresponding session\n```\n\n#### Linking and Unlinking\nYou can link or unlink user accounts with third-party services like Facebook and Twitter as described in: [Linking and Unlinking Users](http://docs.parseplatform.org/rest/guide/#linking-users). To do this, you must first get the corresponding authentication data for the specific service, and then apply it to the user using the linking and unlinking methods. Each method returns true or false if the action was successful. For a listing of supported third-party authentication services, see [OAuth](http://docs.parseplatform.org/parse-server/guide/#oauth-and-3rd-party-authentication).\n\n```ruby\n\nuser = Parse::User.first\n\nfb_auth = { ... } # Facebook auth data\n\n# Link this user's Facebook account with Parse\nuser.link_auth_data! :facebook, fb_auth\n\n# Unlinks this user's Facebook account from Parse\nuser.unlink_auth_data! :facebook\n```\n\n#### Request Password Reset\nYou can reset a user's password using the `Parse::User.request_password_reset` method.\n\n```ruby\nuser = Parse::User.first\n\n# pass a user object\nParse::User.request_password_reset user\n# or email\nParse::User.request_password_reset(\"user@example.com\")\n```\n\n\n## Modeling and Subclassing\nFor the general case, your Parse classes should inherit from `Parse::Object`. `Parse::Object` utilizes features from `ActiveModel` to add several features to each instance of your subclass. These include `Dirty`, `Conversion`, `Callbacks`, `Naming` and `Serializers::JSON`.\n\nTo get started use the `property` and `has_many` methods to setup declarations for your fields. Properties define literal values that are columns in your Parse class. These can be any of the base Parse data types. You will not need to define classes for the basic Parse class types - this includes \"\\_User\", \"\\_Installation\", \"\\_Session\" and \"\\_Role\". These are mapped to `Parse::User`, `Parse::Installation`, `Parse::Session` and `Parse::Role` respectively.\n\nTo get started, you define your classes based on `Parse::Object`. By default, the name of the class is used as the name of the remote Parse class. For a class `Post`, we will assume there is a remote camel-cased Parse table called `Post`. If you need to map the local class name to a different remote class, use the `parse_class` method.\n\n```ruby\nclass Post \u003c Parse::Object\n\t# assumes Parse class \"Post\"\nend\n\nclass Commentary \u003c Parse::Object\n\t# set remote class \"Comment\"\n\tparse_class \"Comment\"\nend\n```\n\n### Defining Properties\nProperties are considered a literal-type of association. This means that a defined local property maps directly to a column name for that remote Parse class which contain the value. **All properties are implicitly formatted to map to a lower-first camelcase version in Parse (remote).** Therefore a local property defined as `like_count`, would be mapped to the remote column of `likeCount` automatically. The only special behavior to this rule is the `:id` property which maps to `objectId` in Parse. This implicit conversion mapping is the default behavior, but can be changed on a per-property basis. All Parse data types are supported and all Parse::Object subclasses already provide definitions for `:id` (objectId), `:created_at` (createdAt), `:updated_at` (updatedAt) and `:acl` (ACL) properties.\n\n- **:string** (_default_) - a generic string. Can be used as an enum field, see [Enum](#enum).\n- **:integer** (alias **:int**) - basic number. Will also generate atomic `_increment!` helper method.\n- **:float** - a floating numeric value. Will also generate atomic `_increment!` helper method.\n- **:boolean** (alias **:bool**) - true/false value. This will also generate a class scope helper. See [Query Scopes](#query-scopes).\n- **:date** - a Parse date type. See [Parse::Date](#parsedate).\n- **:timezone** - a time zone object. See [Parse::TimeZone](#parsetimezone).\n- **:array** - a heterogeneous list with dirty tracking. See [Parse::CollectionProxy](https://github.com/modernistik/parse-stack/blob/master/lib/parse/model/associations/collection_proxy.rb).\n- **:file** - a Parse file type. See [Parse::File](#parsefile).\n- **:geopoint** - a GeoPoint type. See [Parse::GeoPoint](#parsegeopoint).\n- **:bytes** - a Parse bytes data type managed as base64. See [Parse::Bytes](#parsebytes).\n- **:object** - an object \"hash\" data type. See [ActiveSupport::HashWithIndifferentAccess](http://apidock.com/rails/ActiveSupport/HashWithIndifferentAccess).\n\nFor completeness, the `:id` and `:acl` data types are also defined in order to handle the Parse `objectId` field and the `ACL` object. Those are special and should not be used in your class (unless you know what you are doing). New data types can be implemented through the internal `typecast` interface. **TODO: discuss `typecast` interface in the future**\n\nWhen declaring a `:boolean` data type, it will also create a special method that uses the `?` convention. As an example, if you have a property named `approved`, the normal getter `obj.approved` can return true, false or nil based on the value in Parse. However with the `obj.approved?` method, it will return true if it set to true, false for any other value.\n\nWhen declaring an `:integer` or `:float` type, it will also create a special method that performs\nan atomic increment of that field through the `_increment!` and `_decrement!` methods. If you have\ndefined a property named `like_count` for one of these numeric types, which would create the normal getter/setter `obj.like_count`; you can now also call `obj.like_count_increment!` or `obj.like_count_decrement!` to perform the atomic operations (done server side) on this field. You may also pass an amount as an argument to these helper methods such as `obj.like_count_increment!(3)`.\n\nUsing the example above, we can add the base properties to our classes.\n\n```ruby\nclass Post \u003c Parse::Object\n  property :title\n  property :content, :string # explicit\n\n  # treat the values of this field as symbols instead of strings.\n  property :category, :string, symbolize: true\n\n  # maybe a count of comments.\n  property :comment_count, :integer, default: 0\n\n  # use lambda to access the instance object.\n  # Set draft_date to the created_at date if empty.\n  property :draft_date, :date, default: lambda { |x| x.created_at }\n  # the published date. Maps to \"publishDate\"\n  property :publish_date, :date, default: lambda { |x| DateTime.now }\n\n  # maybe whether it is currently visible\n  property :visible, :boolean\n\n  # a list using\n  property :tags, :array\n\n  # string column as enumerated type. see :enum\n  property :status, enum: [:active, :archived]\n\n  # Maps to \"featuredImage\" column representing a File.\n  property :featured_image, :file\n\n  property :location, :geopoint\n\n  # Support bytes\n  property :data, :bytes\n\n  # A field that contains time zone information (ex. 'America/Los_Angeles')\n  property :time_zone, :timezone\n\n  # store SEO information. Make sure we map it to the column\n  # \"SEO\", otherwise it would have implicitly used \"seo\"\n  # as the remote column name\n  property :seo, :object, field: \"SEO\"\nend\n```\n\nAfter properties are defined, you can use appropriate getter and setter methods to modify the values. As properties become modified, the model will keep track of the changes using the [dirty tracking feature of ActiveModel](http://api.rubyonrails.org/classes/ActiveModel/Dirty.html). If an attribute is modified in-place then make use of **[attribute_name]_will_change!** to mark that the attribute is changing. Otherwise ActiveModel can't track changes to in-place attributes.\n\nTo support dirty tracking on properties of data type of `:array`, we utilize a proxy class called `Parse::CollectionProxy`. This class has special functionality which allows lazy loading of content as well and keeping track of the changes that are made. While you are able to access the internal array on the collection through the `#collection` method, it is important not to make in-place edits to the object. You should use the preferred methods of `#add` and `#remove` to modify the contents of the collection. When `#save` is called on the object, the changes will be committed to Parse.\n\n```ruby\npost = Post.first\npost.tags.each do |tag|\n  puts tag\nend\npost.tags.empty? # false\npost.tags.count # 3\narray = post.tags.to_a # get array\n\n# Add\npost.tags.add \"music\", \"tech\"\npost.tags.remove \"stuff\"\npost.save # commit changes\n```\n\n#### Accessor Aliasing\nTo enable easy conversion between incoming Parse attributes, which may be different than the locally labeled attribute, we make use of aliasing accessors with their remote field names. As an example, for a `Post` instance and its `publish_date` property, it would have an accessor defined for both `publish_date` and `publishDate` (or whatever value you passed as the `:field` option) that map to the same attribute. We highly discourage turning off this feature, but if you need to, you can pass the value of `false` to the `:alias` option when defining the property.\n\n```ruby\n # These are equivalent\npost.publish_date = DateTime.now\npost.publishDate = DateTime.now\npost.publish_date == post.publishDate\n\npost.seo # ok\npost.SEO # the alias method since 'field: \"SEO\"'\n```\n\n#### Property Options\nThese are the supported options when defining properties. Parse::Objects are backed by `ActiveModel`, which means you can add additional validations and features supported by that library.\n\n##### `:required`\nA boolean property. This option provides information to the property builder that it is a required property. The requirement is not strongly enforced for a save, which means even though the value for the property may not be present, saves and updates can be successfully performed. However, the setting `required` to true, it will set some ActiveModel validations on the property to be used when calling `valid?`. By default it will add a `validates_presence_of` for the property key. If the data type of the property is either `:integer` or `:float`, it will also add a `validates_numericality_of` validation. Default `false`.\n\n##### `:field`\nThis option allows you to set the name of the remote column for the Parse table. Using this will explicitly set the remote property name to the value of this option. The value provided for this option will affect the name of the alias method that is generated when `alias` option is used. **By default, the name of the remote column is the lower-first camelcase version of the property name. As an example, for a property with key `:my_property_name`, the framework will implicitly assume that the remote column is `myPropertyName`.**\n\n##### `:default`\nThis option provides you to set a default value for a specific property when the getter accessor method is used and the internal value of the instance object's property is nil. It can either take a literal value or a Proc/lambda.\n\n```ruby\nclass SomeClass \u003c Parse::Object\n\t# default value\n\tproperty :category, default: \"myValue\"\n\t# default value Proc style\n\tproperty :date, default: lambda { |x| DateTime.now }\nend\n```\n\n##### `:alias`\nA boolean property. It is highly recommended that this is set to true, which is the default. This option allows for the generation of the additional accessors with the value of `:field`. By allowing two accessors methods, aliased to each other, allows for easier importing and automatic object instantiation based on Parse object JSON data into the Parse::Object subclass.\n\n##### `:symbolize`\nA boolean property. This option is only available for fields with data type of `:string`. This allows you to utilize the values for this property as symbols instead of the literal strings, which is Parse's storage format. This feature is useful if a particular property represents a set of enumerable states described in string form. As an example, if you have a `Post` object which has a set of publish states stored in Parse as \"draft\",\"scheduled\", and \"published\" - we can use ruby symbols to make our code easier.\n\n```ruby\nclass Post \u003c Parse::Object\n\tproperty :state, :string, symbolize: true\nend\n\npost = Post.first\n # the value returned is auto-symbolized\nif post.state == :draft\n\t# will be converted to string when updated in Parse\n\tpost.state = :published\n\tpost.save\nend\n```\n\n##### `:enum`\nThe enum option allows you to define an array of possible values that the particular `:string` property should hold. This feature has similarities in the methods and accessors generated for you as described in [ActiveRecord::Enum](http://edgeapi.rubyonrails.org/classes/ActiveRecord/Enum.html). Using the example in that documentation:\n\n```ruby\nclass Conversation \u003c Parse::Object\n  property :status, enum: [ :active, :archived ]\nend\n\nConversation.statuses # =\u003e [ :active, :archived ]\n\n# named scopes\nConversation.active # where status: :active\nConversation.archived(limit: 10) # where status: :archived, limit 10\n\nconversation.active! # sets status to active!\nconversation.active? # =\u003e true\nconversation.status  # =\u003e :active\n\nconversation.archived!\nconversation.archived? # =\u003e true\nconversation.status    # =\u003e :archived\n\n# equivalent\nconversation.status = \"archived\"\nconversation.status = :archived\n\n# allowed by the setter\nconversation.status = :banana\nconversation.status_valid? # =\u003e false\n\n```\n\nSimilar to [ActiveRecord::Enum](http://edgeapi.rubyonrails.org/classes/ActiveRecord/Enum.html), you can use the `:_prefix` or `:_suffix` options when you need to define multiple enums with same values. If the passed value is true, the methods are prefixed/suffixed with the name of the enum. It is also possible to supply a custom value:\n\n```ruby\nclass Conversation \u003c Parse::Object\n  property :status, enum: [:active, :archived], _suffix: true\n  property :comments_status, enum: [:active, :inactive], _prefix: :comments\n  # combined\n  property :discussion, enum: [:casual, :business], _prefix: :talk, _suffix: true\nend\n\nConversation.statuses # =\u003e [:active, :archived]\nConversation.comments # =\u003e [:active, :inactive]\nConversation.talks # =\u003e [:casual, :business]\n\n# affects scopes names\nConversation.archived_status\nConversation.comments_inactive\nConversation.business_talk\n\nconversation.active_status!\nconversation.archived_status? # =\u003e false\n\nconversation.status = :banana\nconversation.valid_status? # =\u003e false\n\nconversation.comments_inactive!\nconversation.comments_active? # =\u003e false\n\nconversation.casual_talk!\nconversation.business_talk? # =\u003e false\n```\n\n##### `:scope`\nA boolean property. For some data types like `:boolean` and enums, some [query scopes](#query-scopes) are generated to more easily query data. To prevent generating these scopes for a particular property, set this value to `false`.\n\n### Associations\nParse supports a three main types of relational associations. One type of relation is the `One-to-One` association. This is implemented through a specific column in Parse with a Pointer data type. This pointer column, contains a local value that refers to a different record in a separate Parse table. This association is implemented using the `:belongs_to` feature. The second association is of `One-to-Many`. This is implemented is in Parse as a Array type column that contains a list of of Parse pointer objects. It is recommended by Parse that this array does not exceed 100 items for performance reasons. This feature is implemented using the `:has_many` operation with the plural name of the local Parse class. The last association type is a Parse Relation. These can be used to implement a large `Many-to-Many` association without requiring an explicit intermediary Parse table or class. This feature is also implemented using the `:has_many` method but passing the option of `:relation`.\n\n#### Belongs To\nThis association creates a one-to-one association with another Parse model. This association says that this class contains a foreign pointer column which references a different class. Utilizing the `belongs_to` method in defining a property in a Parse::Object subclass sets up an association between the local table and a foreign table. Specifying the `belongs_to` in the class, tells the framework that the Parse table contains a local column in its schema that has a reference to a record in a foreign table. The argument to `belongs_to` should be the singularized version of the foreign Parse::Object class. you should specify the foreign table as the snake_case singularized version of the foreign table class. It is important to note that the reverse relationship is not generated automatically.\n\n```ruby\nclass Author \u003c Parse::Object\n\tproperty :name\nend\n\nclass Comment \u003c Parse::Object\n\tbelongs_to :user # Parse::User\nend\n\nclass Post \u003c Parse::Object\n\tbelongs_to :author\nend\n\npost = Post.first\n # Follow the author pointer and get name\npost.author.name\n\nother_author = Author.first\n # change author by setting new pointer\npost.author = other_author\npost.save\n```\n\n##### Options\nYou can override some of the default functionality when creating both `belongs_to`, `has_one` and `has_many` associations.\n\n###### `:required`\nA boolean property. Setting the requirement, automatically creates an ActiveModel validation of `validates_presence_of` for the association. This will not prevent the save, but affects the validation check when `valid?` is called on an instance. Default is false.\n\n###### `:as`\nThis option allows you to override the foreign Parse class that this association refers while allowing you to have a different accessor name. As an example, you may have a class `Band` which has a `manager` who is of type `Parse::User` and a set of band members, represented by the class `Artist`. You can override the default casting class as follows:\n\n```ruby\n # represents a member of a band or group\nclass Artist \u003c Parse::Object\nend\n\nclass Band \u003c Parse::Object\n\tbelongs_to :manager, as: :user\n\tbelongs_to :lead_singer, as: :artist\n\tbelongs_to :drummer, as: :artist\nend\n\nband = Band.first\nband.manager # Parse::User object\nband.lead_singer # Artist object\nband.drummer # Artist object\n```\n\n###### `:field`\nThis option allows you to set the name of the remote Parse column for this property. Using this will explicitly set the remote property name to the value of this option. The value provided for this option will affect the name of the alias method that is generated when `alias` option is used. **By default, the name of the remote column is the lower-first camel case version of the property name. As an example, for a property with key `:my_property_name`, the framework will implicitly assume that the remote column is `myPropertyName`.**\n\n#### [Has One](https://www.modernistik.com/gems/parse-stack/Parse/Associations/HasOne.html)\nThe `has_one` creates a one-to-one association with another Parse class. This association says that the other class in the association contains a foreign pointer column which references instances of this class. If your model contains a column that is a Parse pointer to another class, you should use `belongs_to` for that association instead.\n\nDefining a `has_one` property generates a helper query method to fetch a particular record from a foreign class. This is useful for setting up the inverse relationship accessors of a `belongs_to`. In the case of the `has_one` relationship, the `:field` option represents the name of the column of the foreign class where the Parse pointer is stored. By default, the lower-first camel case version of the Parse class name is used.\n\nIn the example below, a `Band` has a local column named `manager` which has a pointer to a `Parse::User` record. This setups up the accessor for `Band` objects to access the band's manager.\n\n```ruby\n# every band has a manager\nclass Band \u003c Parse::Object\n\tbelongs_to :manager, as: :user\nend\n\nband = Band.first id: '12345'\n# the user represented by this manager\nuser = band.manger\n\n```\n\nSince we know there is a column named `manager` in the `Band` class that points to a single `Parse::User`, you can setup the inverse association read accessor in the `Parse::User` class. Note, that to change the association, you need to modify the `manager` property on the band instance since it contains the `belongs_to` property.\n\n```ruby\n# every user manages a band\nclass Parse::User\n  # inverse relationship to `Band.belongs_to :manager`\n  has_one :band, field: :manager\nend\n\nuser = Parse::User.first\n# use the generated has_one accessor `band`.\nuser.band # similar to query: Band.first(:manager =\u003e user)\n\n```\n\nYou may optionally use `has_one` with scopes, in order to fine tune the query result. Using the example above, you can customize the query with a scope that only fetches the association if the band is approved. If the association cannot be fetched, `nil` is returned.\n\n```ruby\n# adding to previous example\nclass Band \u003c Parse::Object\n  property :approved, :boolean\n  property :approved_date, :date\nend\n\n# every user manages a band\nclass Parse::User\n  has_one :recently_approved, -\u003e{ where(order: :approved_date.desc) }, field: :manager, as: :band\n  has_one :band_by_status, -\u003e(status) { where(approved: status) },  field: :manager, as: :band\nend\n\n# gets the band most recently approved\nuser.recently_approved\n# equivalent: Band.first(manager: user, order: :approved_date.desc)\n\n# fetch the managed band that is not approved\nuser.band_by_status(false)\n# equivalent: Band.first(manager: user, approved: false)\n\n```\n\n#### [Has Many](https://www.modernistik.com/gems/parse-stack/Parse/Associations/HasMany.html)\nParse has many ways to implement one-to-many and many-to-many associations: `Array`, `Parse Relation` or through a `Query`. How you decide to implement your associations, will affect how `has_many` works in Parse-Stack. Parse natively supports one-to-many and many-to-many relationships using `Array` and `Relations`, as described in [Relational Data](http://docs.parseplatform.org/js/guide/#relational-data). Both of these methods require you define a specific column type in your Parse table that will be used to store information about the association.\n\nIn addition to `Array` and `Relation`, Parse-Stack also implements the standard `has_many` behavior prevalent in other frameworks through a query where the associated class contains a foreign pointer to the local class, usually the inverse of a `belongs_to`. This requires that the associated class has a defined column\nthat contains a pointer the refers to the defining class.\n\n##### Query\nIn this implementation, a `has_many` association for a Parse class requires that another Parse class will have a foreign pointer that refers to instances of this class. This is the standard way that `has_many` relationships work in most databases systems. This is usually the case when you have a class that has a `belongs_to` relationship to instances of the local class.\n\nIn the example below, many songs belong to a specific artist. We set this association by setting `:belongs_to` relationship from `Song` to `Artist`. Knowing there is a column in `Song` that points to instances of an `Artist`, we can setup a `has_many` association to `Song` instances in the `Artist` class. Doing so will generate a helper query method on the `Artist` instance objects.\n\n```ruby\nclass Song \u003c Parse::Object\n  property :released, :date\n  # this class will have a pointer column to an Artist\n  belongs_to :artist\nend\n\nclass Artist \u003c Parse::Object\n  has_many :songs\nend\n\nartist = Artist.first\n\nartist.songs # =\u003e [all songs belonging to artist]\n# equivalent: Song.all(artist: artist)\n\n# filter also by release date\nartist.songs(:released.after =\u003e 1.year.ago)\n# equivalent: Song.all(artist: artist, :released.after =\u003e 1.year.ago)\n\n```\n\nIn order to modify the associated objects (ex. `songs`), you must modify their corresponding `belongs_to` field (in this case `song.artist`), to another record and save it.\n\nOptions for `has_many` using this approach are `:as` and `:field`. The `:as` option behaves similarly to the `:belongs_to` counterpart. The `:field` option can be used to override the derived column name located in the foreign class. The default value for `:field` is the columnized version of the Parse subclass `parse_class` method.\n\n```ruby\nclass Parse::User\n  # since the foreign column name is :agent\n  has_many :artists, field: :agent\nend\n\nclass Artist \u003c Parse::Object\n  belongs_to :manager, as: :user, field: :agent\nend\n\nartist.manager # =\u003e Parse::User object\n\nuser.artists # =\u003e [artists where :agent column is user]\n```\n\nWhen using this approach, you may also employ the use of scopes to filter the particular data from the `has_many` association.\n\n```ruby\nclass Artist\n  has_many :songs, -\u003e(timeframe) { where(:created_at.after =\u003e timeframe) }\nend\n\nartist.songs(6.months.ago)\n# =\u003e [artist's songs created in the last 6 months]\n\n```\n\nYou may also call property methods in your scopes related to the local class. You also have access to the instance object for the local class through a special `:i` method in the scope.\n\n```ruby\nclass Concert\n  property :city\n  belongs_to :artist\nend\n\nclass Artist\n  property :hometown\n  has_many :local_concerts, -\u003e { where(:city =\u003e hometown) }, as: :concerts\nend\n\n# assume\nartist.hometown = \"San Diego\"\n\n# artist's concerts in their hometown of 'San Diego'\nartist.local_concerts\n# equivalent: Concert.all(artist: artist, city: artist.hometown)\n\n```\n\n##### Array\nIn this implementation, you can designate a column to be of `Array` type that contains a list of Parse pointers. Parse-Stack supports this by passing the option `through: :array` to the `has_many` method. If you use this approach, it is recommended that this is used for associations where the quantity is less than 100 in order to maintain query and fetch performance. You would be in charge of maintaining the array with the proper list of Parse pointers that are associated to the object. Parse-Stack does help by wrapping the array in a [Parse::PointerCollectionProxy](https://github.com/modernistik/parse-stack/blob/master/lib/parse/model/associations/pointer_collection_proxy.rb) which provides dirty tracking.\n\n```ruby\nclass Artist \u003c Parse::Object\nend\n\nclass Band \u003c Parse::Object\n\thas_many :artists, through: :array\nend\n\nartist = Artist.first\n\n# find all bands that contain this artist\nbands = Band.all( :artists.in =\u003e [artist.pointer] )\n\nband = bands.first\nband.artists # =\u003e [array of Artist pointers]\n\n# remove artists\nband.artists.remove artist\n\n# add artist\nband.artists.add artist\n\n# save changes\nband.save\n```\n\n##### Parse Relation\nOther than the use of arrays, Parse supports native one-to-many and many-to-many associations through what is referred to as a [Parse Relation](http://docs.parseplatform.org/js/guide/#many-to-many-relationships). This is implemented by defining a column to be of type `Relation` which refers to a foreign class. Parse-Stack supports this by passing the `through: :relation` option to the `has_many` method. Designating a column as a Parse relation to another class type, will create a one-way intermediate \"join-list\" between the local class and the foreign class. One important distinction of this compared to other types of data stores (ex. PostgresSQL) is that:\n\n1. The inverse relationship association is not available automatically. Therefore, having a column of `artists` in a `Band` class that relates to members of the band (as `Artist` class), does not automatically make a set of `Band` records available to `Artist` records for which they have been related. If you need to maintain both the inverse relationship between a foreign class to its associations, you will need to manually manage that by adding two Parse relation columns in each class, or by creating a separate class (ex. `ArtistBands`) that is used as a join table.\n2. Querying the relation is actually performed against the implicit join table, not the local one.\n3. Applying query constraints for a set of records within a relation is performed against the foreign table class, not the class having the relational column.\n\nThe Parse documentation provides more details on associations, see [Parse Relations Guide](http://docs.parseplatform.org/ios/guide/#relations). Parse-Stack will handle the work for (2) and (3) automatically.\n\nIn the example below, a `Band` can have thousands of `Fans`. We setup a `Relation\u003cFan\u003e` column in the `Band` class that references the `Fan` class. Parse-Stack provides methods to manage the relationship under the [Parse::RelationCollectionProxy](https://github.com/modernistik/parse-stack/blob/master/lib/parse/model/associations/relation_collection_proxy.rb) class.\n\n```ruby\n\nclass Fan \u003c Parse::Object\n  # .. lots of properties ...\n\tproperty :location, :geopoint\nend\n\nclass Band \u003c Parse::Object\n\thas_many :fans, through: :relation \nend\n\nband = Band.first\n\n # the number of fans in the relation\nband.fans.count\n\n# get the first object in relation\nfan = bands.fans.first # =\u003e Parse::User object\n\n# use `add` or `remove` to modify relations\nband.fans.add user\nband.fans.add_unique user # no op\nbands.fans.remove user\n\n# updates the relation as well as changes to `band`\nband.fans.save\n\n# Find 50 fans who are near San Diego, CA\ndowntown = Parse::GeoPoint.new(32.82, -117.23)\nfans = band.fans.all :location.near =\u003e downtown\n\n```\n\nYou can perform atomic additions and removals of objects from `has_many` relations. Parse allows this by providing a specific atomic operation request. You can use the methods below to perform these types of atomic operations. __Note: The operation is performed directly on Parse server and not on your instance object.__\n\n```ruby\n\n# atomically add/remove\nband.artists.add! objects  # { __op: :AddUnique }\nband.artists.remove! objects  # { __op: :AddUnique }\n\n# atomically add unique Artist\nband.artists.add_unique! objects  # { __op: :AddUnique }\n\n# atomically add/remove relations\nband.fans.add! users # { __op: :Add }\nband.fans.remove! users # { __op: :Remove }\n\n# atomically perform a delete operation on this field name\n# this should set it as `undefined`.\nband.op_destroy!(\"category\") # { __op: :Delete }\n\n```\n\nYou can also perform queries against class entities to find related objects. Assume\nthat users can like a band. The `Band` class can have a `likes` column that is\na Parse relation to the `Parse::User` class containing the users who have liked a\nspecific band.\n\n```ruby\n  # assume the schema\n  class Band \u003c Parse::Object\n    # likes is a Parse relation column of user objects.\n    has_many :likes, through: :relation, as: :user\n  end\n```\n\nYou can now find all `Parse::User` records that have \"liked\" a specific band. *In the\nexample below, the `:likes` key refers to the `likes` column defined in the `Band`\ncollection which contains the set of user records.*\n\n```ruby\n  band = Band.first # get a band\n  # find all users who have liked this band, where :likes is a column\n  # in the Band collection - NOT in the User collection.\n  users = Parse::User.all :likes.related_to =\u003e band\n\n  # or use the relation accessor in band. It is equivalent since Band is\n  # declared with a :has_many association.\n  band.likes.all # =\u003e array of Parse::Users who liked the band\n```\nYou can also find all bands that a specific user has liked.\n\n```ruby\n  user = Parse::User.first\n  # find all bands where this user is contained in the `likes` Parse relation column\n  # of the Band collection\n  bands_liked_by_user = Band.all :likes =\u003e user\n```\n\n##### Options\nOptions for `has_many` are the same as the `belongs_to` counterpart with support for `:required`, `:as` and `:field`. It has these additional options.\n\n###### `:through`\nThis sets the type of the `has_many` relation whose possible values are `:array`, `:relation` or `:query` (implicit default). If set to `:array`, it defines the column in Parse as being an array of Parse pointer objects and will be managed locally using a `Parse::PointerCollectionProxy`. If set to `:relation`, it defines a column of type Parse Relation with the foreign class and will be managed locally using a `Parse::RelationCollectionProxy`. If set to `:query`, no storage is required on the local class as the associated records will be fetched using a Parse query.\n\n###### `:scope_only`\nSetting this option to `true`, makes the association fetch based only on the scope provided and does not use the local instance object as a foreign pointer in the query. This allows for cases where another property of the local class, is needed to match the resulting records in the association.\n\nIn the example below, the `Post` class does not have a `:belongs_to` association to `Author`, but using the author's name, we can find related posts.\n\n```ruby\n\nclass Author \u003c Parse::Object\n  property :name\n  has_many :posts, -\u003e{ where :tags.in =\u003e name.downcase }, scope_only: true\nend\n\nclass Post \u003c Parse::Object\n  property :tags, :array\nend\n\nauthor.posts # =\u003e Posts where author's name is a tag\n# equivalent: Post.all( :tags.in =\u003e artist.name.downcase )\n\n```\n\n## Creating, Saving and Deleting Records\nThis section provides some of the basic methods when creating, updating and deleting objects from Parse. Additional documentation for these APIs can be found under [Parse::Core::Actions](https://www.modernistik.com/gems/parse-stack/Parse/Core/Actions.html). To illustrate the various methods available for saving Parse records, we use this example class:\n\n```ruby\n\nclass Artist \u003c Parse::Object\n  property :name\n  belongs_to :manager, as: :user\nend\n\nclass Song \u003c Parse::Object\n\tproperty :name\n\tproperty :audio_file, :file\n\tproperty :released, :date\n\tproperty :available, :boolean, default: true\n\tbelongs_to :artist\n\thas_many :fans, as: :user, through: :relation\nend\n```\n\n### Create\nTo create a new object you can call `#new` while passing a hash of attributes you want to set. You can then use the property accessors to also modify individual properties. As you modify properties, you can access dirty tracking state and data using the generated [`ActiveModel::Dirty`](http://api.rubyonrails.org/classes/ActiveModel/Dirty.html) features. When you are ready to commit the new object to Parse, you can call `#save`.\n\n```ruby\nsong = Song.new name: \"My Old Song\"\nsong.new? # true\nsong.id # nil\nsong.released = DateTime.now\nsong.changed? # true\nsong.changed # ['name', 'released']\nsong.name_changed? # true\n\n# commit changes\nsong.save\n\nsong.new? # false\nsong.id # 'hZLbW6ofKC'\nsong.name = \"My New Song\"\nsong.name_was # \"My Old Song\"\nsong.changed # ['name']\n\n```\n\nIf you want to either find the first resource matching some given criteria or just create that resource if it can't be found, you can use `first_or_create`. Note that if a match is not found, the object will not be saved to Parse automatically, since the framework provides support for heterogeneous object batch saving. This means you can group different object classes together and save them all at once through the `Array#save` method to reduce API requests. If you want to truly want to find a first or create (save) the object, you may use `first_or_create!`.\n\n```ruby\n # Finds matching song or creates a new unsaved object\nsong = Song.first_or_create(name: \"Awesome Song\", available: true)\nsong.id # nil since it wasn't found, and autosave is off.\nsong.released = 1.day.from_now\nsong.save\nsong.id # now has a valid objectId ex. 'xyz1122df'\n\nsong = Song.first_or_create(name: \"Awesome Song\", available: true)\nsong.id # 'xyz1122df`\nsong.save # noop since nothing changed\n\n# first_or_create! : Return an existing OR newly saved object\nsong = Song.first_or_create!(name: \"Awesome Song\", available: true)\n\n```\n\nIf the constraints you use for the query differ from the attributes you want to set for the new object, you can pass the attributes for creating a new resource as the second parameter to `#first_or_create`, also in the form of a `#Hash`.\n\n```ruby\n  song = Song.first_or_create({ name: \"Long Way Home\" }, { released: DateTime.now })\n```\n\nThe above will search for a Song with name 'Long Way Home'. If it does not find a match, it will create a new instance with `name` set to 'Long Way Home' and the `released` date field to the current time, at time of execution. In this scenario, both hash arguments are merged to create a new instance with the second set of arguments overriding the first set.\n\n```ruby\n  song = Song.first_or_create({ name: \"Long Way Home\" }, {\n          name: \"Other Way Home\",\n          released: DateTime.now # Time.now ok too\n    })\n```\n\nIn the above case, if a Song is not found with name 'Long Way Home', the new instance will be created with `name` set to 'Other Way Home' and `released` set to `DateTime.now`.\n\n### Saving\nTo commit a new record or changes to an existing record to Parse, use the `#save` method. The method will automatically detect whether it is a new object or an existing one and call the appropriate workflow. The use of ActiveModel dirty tracking allows us to send only the changes that were made to the object when saving. **Saving a record will take care of both saving all the changed properties, and associations. However, any modified linked objects (ex. belongs_to) need to be saved independently.**\n\n```ruby\n song = Song.new(name: \"Awesome Song\") # Pass in a hash to the new method\n song.name = \"Super Song\" # Set individual property\n\n # Set multiple properties at once\n song.attributes = { name: \"Best Song\", released: DateTime.now }\n\n song.artist = Artist.first\n song.artist.name = \"New Band Name\"\n # add a fan to this song. Note this is a Parse Relation\n song.fans.add = Parse::User.first\n\n # saves changed properties, associations and relations.\n song.save\n\n song.artist.save # to commit the changes made to 'name'.\n\n songs = Song.all( :available =\u003e false)\n songs.each { |song| song.available = true }\n\n # uses a Parse batch operation for efficiency\n songs.save # save the rest of the items\n```\n\nThe save operation can handle both creating and updating existing objects. If you do not want to update the association data of a changed object, you may use the `#update` method to only save the changed property values. In the case where you want to force update an object even though it has not changed, to possibly trigger your `before_save` hooks, you can use the `#update!` method. In addition, just like with other ActiveModel objects, you may call `reload!` to fetch the current record again from the data store.\n\n### Saving applying User ACLs\nYou may save and delete objects from Parse on behalf of a logged in user by passing the session token to the call to `save` or `destroy`. Doing so will allow Parse to apply the ACLs of this user against the record to see if the user is authorized to read or write the record. See [Parse::Actions](https://www.modernistik.com/gems/parse-stack/Parse/Core/Actions.html).\n\n```ruby\n  user = Parse::User.login('myuser','pass')\n\n  song = Song.first\n  song.title = \"My New Title\"\n  # save this song as if you were this user.\n  # If the user does not have access rights, it will fail\n  song.save session: user.session_token\n  # shorthand: song.save session: user\n```\n\n#### Raising an exception when save fails\nBy default, we return `true` or `false` for save and destroy operations. If you prefer to have `Parse::Object` raise an exception instead, you can tell to do so either globally or on a per-model basis. When a save fails, it will raise a `Parse::RecordNotSaved`.\n\n```ruby\n # globally across all models\n Parse::Model.raise_on_save_failure = true\n Song.raise_on_save_failure = true  # per-model\n\n # or per-instance raise on failure\n song.save!\n```\n\nWhen enabled, if an error is returned by Parse due to saving or destroying a record, due to your `before_save` or `before_delete` validation cloud code triggers, `Parse::Object` will return the a `Parse::RecordNotSaved` exception type. This exception has an instance method of `#object` which contains the object that failed to save.\n\n### Modifying Associations\nSimilar to `:array` types of properties, a `has_many` association is backed by a collection proxy class and requires the use of `#add` and `#remove` to modify the contents of the association in order for it to correctly manage changes and updates with Parse. Using `has_many` for associations has the additional functionality that we will only add items to the association if they are of a `Parse::Pointer` or `Parse::Object` type. By default, these associations are fetched with only pointer data. To fetch all the objects in the association, you can call `#fetch` or `#fetch!` on the collection. Note that because the framework supports chaining, it is better to only request the objects you need by utilizing their accessors.\n\n```ruby\n  class Artist \u003c Parse::Object\n    has_many :songs # array association\n  end\n\n  artist = Artist.first\n  artist.songs # Song pointers\n\n  # fetch all the objects in this association\n  artist.songs.fetch # fetches with parallel requests\n\n  # add another song\n  artist.songs.add Song.first\n  artist.songs.remove other_song\n  artist.save # commits changes\n```\n\nFor the cases when you want to modify the items in this association without having to fetch all the objects in the association, we provide the methods `#add!`, `#add_unique!`, `#remove!` and `#destroy` that perform atomic Parse operations. These Parse operations are made directly to Parse compared to the non-bang versions which are batched with the rest of the pending object changes.\n\n```ruby\n  artist = Artist.first\n  artist.songs.add! song # Add operation\n  artist.songs.add_unique! other_song # AddUnique operation\n  artist.songs.remove! another_song # Remove operation\n  artist.save # no-op. (no operations were sent directly to Parse)\n\n  artist.songs.destroy! # Delete operation of all Songs\n```\n\nThe `has_many` Parse Relation associations are handled similarly as in the array cases above. However, since a Parse Relation represents a separate table, there are additional methods provided in order to query the intermediate relational table.\n\n```ruby\n  song = Song.first\n\n  # Standard methods, but through relation table\n  song.fans.count # efficient counting\n  song.fans.add user\n  song.fans.remove another_user\n  song.save # commit changes\n\n  # OR use to commit ONLY relational changes\n  song.fans.save\n\n  # Additional filtering methods\n\n  # Find objects within the relation that match query constraints\n  song.fans.all( ... constraints ... )\n\n  # get a foreign relational query, related to this object\n  query = song.fans.query\n\n  # Atomic operations\n  song.fans.add! user # AddRelation operation\n  song.fans.remove! user # RemoveRelation operation\n  song.fans.destroy! #noop since Relations cannot be emptied.\n\n```\n\n### Batch Requests\nBatch requests are supported implicitly and intelligently through an extension of Array. When an array of `Parse::Object` subclasses is saved, Parse-Stack will batch all possible save operations for the objects in the array that have changed. It will also batch save 50 at a time until all items in the array are saved. The objects do not have to be of the same collection in order to be supported in the batch request. *Note: Parse does not allow batch saving Parse::User objects.*\n\n```ruby\nsongs = Songs.first 1000 #first 1000 songs\nsongs.each do |song|\n  .... modify them ...\nend\n\n# will batch save 50 items at a time until all are saved.\nsongs.save\n\n# you can also destroy a set of objects\nsongs.destroy\n```\n\n### Magic `save_all`\nBy default, all Parse queries have a maximum fetch limit of 1000. While using the `:max` option, Parse-Stack can increase this up to 11,000. In the cases where you need to update a large number of objects, you can utilize the `Parse::Object#save_all` method to fetch, modify and save objects.\n\nThis methodology works by continually fetching and saving older records related to the time you begin a `save_all` request (called an \"anchor date\"), until there are no records left to update. To enable this to work, you must have confidence that any modifications you make to the records will successfully save through you validations that may be present in your `before_save`. This is important, as saving a record will set its `updated_at` date to one newer than the \"anchor date\" of when the `save_all` started. This `save_all` process will stop whenever no more records match the provided constraints that are older than the \"anchor date\", or when an object that was previously updated, is seen again in a future fetch (_which means the object failed to save_). Note that `save_all` will automatically manage the correct `updated_at` constraints in the query, so it is recommended that you do not use it as part of the initial constraints.\n\n```ruby\n  # Add any constraints except `updated_at`.\n  Song.save_all( available: false) do |song|\n    song.available = true # make all songs available\n    # only objects that were modified will be updated\n  \t# do not call save. We will batch objects for saving.\n  end\n```\n\nIf you plan on using this feature in a lot of places, we recommend making sure you have set a MongoDB index of at least `{ \"_updated_at\" : 1 }`.\n\n### Deleting\nYou can destroy a Parse record, just call the `#destroy` method. It will return a boolean value whether it was successful.\n\n```ruby\n song = Song.first\n song.destroy\n\n # or in a batch\n songs = Song.all :limit =\u003e 10\n songs.destroy # uses batch operation\n```\n\n## Fetching, Finding and Counting Records\n\n```ruby\n song = Song.find \"\u003cobjectId\u003e\"\n        Song.get  \"\u003cobjectId\u003e\" # alias\n\n song1, song2 = Song.find(\"\u003cobjectId\u003e\", \"\u003cobjectId2\u003e\", ...) # fetches in parallel with threads\n\n count = Song.count( constraints ) # performs a count operation\n\n query = Song.where( constraints ) # returns a Parse::Query with where clauses\n song = Song.first( ... constraints ... ) # first Song matching constraints\n s1, s2, s3 = Song.first(3) # get first 3 records from Parse.\n\n songs = Song.all( ... expressions ...) # get matching Song records. See Advanced Querying\n\n # memory efficient for large amounts of records if you don't need all the objects.\n # Does not return results after loop.\n Song.all( ... expressions ...) do |song|\n   # ... do something with song..\n end\n\n```\n\n### Auto-Fetching Associations\nAll associations in are fetched lazily by default. If you wish to include objects as part of your query results you can use the `:includes` expression.\n\n```ruby\n  song = Song.first\n  song.artist.pointer? # true, not fetched\n\n  # find songs and include the full artist object for each\n  song = Song.first(:includes =\u003e :artist)\n  song.artist.pointer? # false (Full object already available)\n\n```\n\nHowever, Parse-Stack performs automatic fetching of associations when the associated classes and their properties are locally defined. Using our Artist and Song examples. In this example, the Song object fetched only has a pointer object in its `#artist` field. However, because the framework knows there is a `Artist#name` property, calling `#name` on the artist pointer will automatically go to Parse to fetch the associated object and provide you with the value.\n\n```ruby\n  song = Song.first\n  # artist is automatically fetched\n  song.artist.name\n\n  # You can manually do the same with `fetch` and `fetch!`\n  song.artist.fetch # considered \"fetch if needed\". No-op if not needed.\n  song.artist.fetch! # force fetch regardless of state.\n```\n\nThis also works for all associations types.\n\n```ruby\n  song = Song.first\n  # automatically fetches all pointers in the chain\n  song.artist.manager.username # Parse::User's username\n\n  # Fetches Parse Relation objects\n  song.fans.first.username # the fan's username\n```\n\n## Advanced Querying\nThe `Parse::Query` class provides the lower-level querying interface for your Parse tables using the default `Parse::Client` session created when `setup()` was called. This component can be used on its own without defining your models as all results are provided in hash form. By convention in Ruby (see [Style Guide](https://github.com/bbatsov/ruby-style-guide#snake-case-symbols-methods-vars)), symbols and variables are expressed in lower_snake_case form. Parse, however, prefers column names in **lower-first camel case** (ex. `objectId`, `createdAt` and `updatedAt`). To keep in line with the style guides between the languages, we do the automatic conversion of the field names when compiling the query. As an additional exception to this rule, the field key of `id` will automatically be converted to the `objectId` field when used. This feature can be overridden by changing the value of `Parse::Query.field_formatter`.\n\n```ruby\n# default uses :columnize\nquery = Parse::User.query :field_one =\u003e 1, :FieldTwo =\u003e 2, :Field_Three =\u003e 3\nquery.compile_where # {\"fieldOne\"=\u003e1, \"fieldTwo\"=\u003e2, \"fieldThree\"=\u003e3}\n\n# turn off\nParse::Query.field_formatter = nil\nquery = Parse::User.query :field_one =\u003e 1, :FieldTwo =\u003e 2, :Field_Three =\u003e 3\nquery.compile_where # {\"field_one\"=\u003e1, \"FieldTwo\"=\u003e2, \"Field_Three\"=\u003e3}\n\n# force everything camel case\nParse::Query.field_formatter = :camelize\nquery = Parse::User.query :field_one =\u003e 1, :FieldTwo =\u003e 2, :Field_Three =\u003e 3\nquery.compile_where # {\"FieldOne\"=\u003e1, \"FieldTwo\"=\u003e2, \"FieldThree\"=\u003e3}\n\n```\n\nSimplest way to perform query, is to pass the Parse class as the first parameter and the set of expressions.\n\n```ruby\n query = Parse::Query.new(\"Song\", {.... expressions ....})\n # or with Object classes\n query = Song.query({ .. expressions ..})\n\n # Print the prepared query\n query.prepared\n\n # Get results\n query.results # get results as Parse::Object(s)\n query.results(raw: true) # get the raw hash results\n\n query.first # first results matching constraints\n query.first(3) # gets first 3 results matching constraints\n\n query.count # perform a count operation instead\n```\n\nFor large results set where you may want to operate on objects and may not need to keep all the objects in memory, you can use the block version of the API to iterate through all the records more efficiently.\n\n```ruby\n\n # For large results set, you can use the block version to iterate over each matching record\n query.each do |record|\n\t# ... do something with record ...\n\t# block version does not return results\n end\n\n```\n\n### Results Caching\nWhen a query API is made, the results are cached in the query object in case you need access to the results multiple times. This is only true as long as no modifications to the query parameters are made. You can force clear the locally stored results by calling `clear()` on the query instance.\n\n```ruby\n query = Parse::Query.new(\"Song\")\n query.where :field =\u003e value\n\n query.results # makes request\n # no query parameters changed, therefore same results\n query.results # no API request\n\n # if you modify the query or call 'clear'\n query.clear\n query.results # makes API request\n\n```\n\n### Counting\nIf you only need to know the result count for a query, provide count a\nnon-zero value. However, if you need to perform a count query, use `count()` method instead.\n\n```ruby\n # get number of songs with a play_count \u003e 10\n Song.count :play_count.gt =\u003e 10\n\n # same\n query = Parse::Query.new(\"Song\")\n query.where :play_count.gt =\u003e 10\n query.count\n\n```\n\n### Distinct Aggregation\nFinds the distinct values for a specified field across a single collection or\nview and returns the results in an array. You may mix this with additional query constraints.\n\n```ruby\n # Return a list of unique city names\n # for users created in the last 10 days.\n User.distinct :city, :created_at.after =\u003e 10.days.ago\n # ex. [\"San Diego\", \"Los Angeles\", \"San Juan\"]\n\n # same\n query = Parse::Query.new(\"_User\")\n query.where :created_at.after =\u003e 10.days.ago\n query.distinct(:city) #=\u003e [\"San Diego\", \"Los Angeles\", \"San Juan\"]\n\n```\n\n### Query Expressions\nThe set of supported expressions based on what is available through the Parse REST API. _For those who don't prefer the DataMapper style syntax, we have provided method accessors for each of the expressions._ A full description of supported query  operations, please refer to the [`Parse::Query`](https://www.modernistik.com/gems/parse-stack/Parse/Query.html) API reference.\n\n#### :order\nSpecify a field to sort by.\n\n```ruby\n # order updated_at ascending order\n Song.all :order =\u003e :updated_at\n\n # first order by highest like_count, then by ascending name.\n # Note that ascending is the default if not specified (ex. `:name.asc`)\n Song.all :order =\u003e [:like_count.desc, :name]\n```\n\n#### :keys\nRestrict the fields returned by the query. This is useful for larger query results set where some of the data will not be used, which reduces network traffic and deserialization performance. _Use this feature with caution when working with the results, as values for the fields not specified in the query will be omitted in the resulting object._\n\n```ruby\n # results only contain :name field\n Song.all :keys =\u003e :name\n\n # multiple keys\n Song.all :keys =\u003e [:name,:artist]\n```\n\n#### :includes\nUse on Pointer columns to return the full object. You may chain multiple columns with the `.` operator.\n\n```ruby\n # assuming an 'Artist' has a pointer column for a 'Manager'\n # and a Song has a pointer column for an 'Artist'.\n\n # include the full artist object\n Song.all(:includes =\u003e :artist)\n\n # Chaining\n Song.all :includes =\u003e [:artist, 'artist.manager']\n\n```\n\n#### :limit\nLimit the number of objects returned by the query. The default is 100, with Parse allowing a maximum of 1000. The framework also allows a value of `:max`. Utilizing this will have the framework continually intelligently utilize `:skip` to continue to paginate through results until an empty result set is received or the `:skip` limit is reached. When utilizing `all()`, `:max` is the default option for `:limit`.\n\n```ruby\n Song.all :limit =\u003e 1 # same as Song.first\n Song.all :limit =\u003e 1000 # maximum allowed by Parse\n Song.all :limit =\u003e :max\n```\n\n#### :skip\nUse with limit to paginate through results. Default is 0.\n\n```ruby\n # get the next 3 songs after the first 10\n Song.all :limit =\u003e 3, :skip =\u003e 10\n```\n\n#### :cache\nA `true`, `false` or integer value. If you are using the built-in caching middleware, `Parse::Middleware::Caching`, setting this to `false` will prevent it from using a previously cached result if available. You may pass an integer value, which will allow this request to be cached for the specified number of seconds. The default value is `true`, which uses the [`:expires`](#expires) value that was passed when [configuring the client](#connection-setup).\n\n```ruby\n# don't use a cached result if available\nSong.all limit: 500, cache: false\n\n# cache this particular request for 60 seconds\nSong.all limit: 500, cache: 1.minute\n```\n\nYou may access the shared cache for the default client connection through `Parse.cache`. This is useful if you\nwant to utilize the same cache store for other purposes.\n\n```ruby\n# Access the cache instance for other uses\nParse.cache[\"key\"] = \"value\"\nParse.cache[\"key\"] # =\u003e \"value\"\n\n# or with Parse queries and objects\nParse.cache.fetch(\"all:song:records\") do |key|\n  results = Song.all # or other complex query or operation\n  # store it in the cache, but expires in 30 seconds\n  Parse.cache.store(key, results, expires: 30)\nend\n\n```\n\n#### :use_master_key\nA true/false value. If you provided a master key as part of `Parse.setup()`, it will be sent on every request. However, if you wish to disable sending the master key on a particular request in order for the record ACLs to be enforced, you may pass `false`. If `false` is passed, caching will be disabled for this request.\n\n```ruby\n# disable sending the master key in the request if configured\nSong.all limit: 3, use_master_key: false\n```\n\n#### :session\nThis will make sure that the query is performed on behalf (and with the privileges) of an authenticated user which will cause record ACLs to be enforced. If a session token is provided, caching will be disabled for this request. You may pass a string representing the session token, an authenticated `Parse::User` instance or a `Parse::Session` instance.\n\n```ruby\n# disable sending the master key in the request if configured\n# and perform this request as a Parse user represented by this token\nSong.all limit: 3, session: \"\u003csession_token\u003e\"\nSong.all limit: 3, session: user # a logged-in Parse::User\nSong.all limit: 3, session: session # Parse::Session\n```\n\n#### :where\nThe `where` clause is based on utilizing a set of constraints on the defined column names in your Parse classes. The constraints are implemented as method operators on field names that are tied to a value. Any symbol/string that is not one of the main expression keywords described here will be considered as a type of query constraint for the `where` clause in the query. See the section `Query Constraints` for examples of available query constraints.\n\n```ruby\n# parts of a single where constraint\n{ :column.constraint =\u003e value }\n```\n\n## [Query Constraints](https://www.modernistik.com/gems/parse-stack/Parse/Constraint.html)\nMost of the constraints supported by Parse are available to `Parse::Query`. Assuming you have a column named `field`, here are some examples. For an explanation of the constraints, please see [Parse Query Constraints documentation](http://docs.parseplatform.org/rest/guide/#queries). You can build your own custom query constraints by creating a `Parse::Constraint` subclass. For all these `where` clauses assume `q` is a `Parse::Query` object.\n\n#### Equals\nDefault query constraint for matching a field to a single value.\n\n```ruby\nq.where :field =\u003e value\n# (alias) :field.eq =\u003e value\n```\n\nIf you want to see if a particular field contains a specific Parse::Object (pointer), you can use the following:\n\n```ruby\n# find rows where the `field` contains a Parse \"_User\" pointer with the specified objectId.\nq.where :field =\u003e Parse::Pointer.new(\"_User\", \"anObjectId\")\n# alias using subclass helper\nq.where :field =\u003e Parse::User.pointer(\"anObjectId\")\n# alias using `:id` constraint. We will infer :user maps to class \"_User\" (Parse::User)\nq.where :user.id =\u003e \"anObjectId\"\n```\n\n#### Less Than\nEquivalent to the `$lt` Parse query operation. The alias `before` is provided for readability.\n\n```ruby\nq.where :field.lt =\u003e value\n# or alias\nq.where :field.before =\u003e value\n# ex. :createdAt.before =\u003e DateTime.now\n```\n\n#### Less Than or Equal To\nEquivalent to the `$lte` Parse query operation. The alias `on_or_before` is provided for readability.\n\n```ruby\nq.where :field.lte =\u003e value\n# or alias\nq.where :field.on_or_before =\u003e value\n# ex. :createdAt.on_or_before =\u003e DateTime.now\n```\n\n#### Greater Than\nEquivalent to the `$gt` Parse query operation. The alias `after` is provided for readability.\n\n```ruby\nq.where :field.gt =\u003e value\n# or alias\nq.where :field.after =\u003e value\n# ex. :createdAt.after =\u003e DateTime.now\n```\n\n#### Greater Than or Equal\nEquivalent to the `$gte` Parse query operation. The alias `on_or_after` is provided for readability.\n\n```ruby\nq.where :field.gte =\u003e value\n# or alias\nq.where :field.on_or_after =\u003e value\n# ex. :createdAt.on_or_after =\u003e DateTime.now\n```\n\n#### Not Equal To\nEquivalent to the `$ne` Parse query operation. Where a particular field is not equal to value.\n\n```ruby\nq.where :field.not =\u003e value\n```\n\n#### Nullability Check\nProvides a mechanism using the equality operator to check for `(undefined)` values.\n\n```ruby\nq.where :field.null =\u003e true|false\n```\n\n#### Exists\nEquivalent to the `#exists` Parse query operation. Checks whether a value is set for key. The difference between this operation and the nullability check is when using compound queries with location.\n\n```ruby\nq.where :field.exists =\u003e true|false\n```\n\n#### Contained In\nEquivalent to the `$in` Parse query operation. Checks whether the value in the column field is contained in the set of values in the target array. If the field is an array data type, it checks whether at least one value in the field array is contained in the set of values in the target array.\n\n```ruby\n# ex. :score.in =\u003e [1,3,5,7,9]\nq.where :field.in =\u003e [item1,item2,...]\n# alias\nq.where :field.contained_in =\u003e [item1,item2,...]\n```\n\n#### Not Contained In\nEquivalent to the `$nin` Parse query operation. Checks whether the value in the column field is __not__ contained in the set of values in the target array. If the field is an array data type, it checks whether at least one value in the field array is __not__ contained in the set of values in the target array.\n\n```ruby\n# ex. :player_name.not_in =\u003e ['Jonathan', 'Dario', 'Shawn']\nq.where :field.not_in =\u003e [item1,item2,...]\n# alias\nq.where :field.not_contained_in =\u003e [item1,item2,...]\n```\n\n#### Contains All\nEquivalent to the `$all` Parse query operation. Checks whether the value in the column field contains all of the given values provided in the array. Note that the `field` column should be of type `Array` in your Parse class.\n\n```ruby\n # ex. :array_key.all =\u003e [2,3,4]\n q.where :field.all =\u003e [item1, item2,...]\n # alias\n q.where :field.contains_all =\u003e [item1,item2,...]\n```\n\n#### Regex Matching\nEquivalent to the `$regex` Parse query operation. Requires that a field value match a regular expression.\n\n```ruby\n# ex. :name.like =\u003e /Bob/i\nq.where :field.like =\u003e /ruby_regex/i\n# alias\nq.where :field.regex =\u003e /abc/\n```\n\n#### Select\nEquivalent to the `$select` Parse query operation. This matches a value for a key in the result of a different query.\n\n```ruby\nq.where :field.select =\u003e { key: \"field\", query: query }\n\n# example\nvalue = { key: 'city', query: Artist.where(:fan_count.gt =\u003e 50) }\nq.where :hometown.select =\u003e value\n\n# if the local field is the same name as the foreign table field, you can omit hash\n# assumes key: 'city'\nq.where :city.select =\u003e Artist.where(:fan_count.gt =\u003e 50)\n```\n\n#### Reject\nEquivalent to the `$dontSelect` Parse query operation. Requires that a field's value not match a value for a key in the result of a different query.\n\n```ruby\nq.where :field.reject =\u003e { key: :other_field, query: query }\n\n# example\nvalue = { key: 'city', query: Artist.where(:fan_count.gt =\u003e 50) }\nq.where :hometown.reject =\u003e value\n\n# if the local field is the same name as the foreign table field, you can omit hash\n# assumes key: 'city'\nq.where :city.reject =\u003e Artist.where(:fan_count.gt =\u003e 50)\n```\n\n#### Matches Query\nEquivalent to the `$inQuery` Parse query operation. Useful if you want to retrieve objects where a field contains an object that matches another query.\n\n```ruby\nq.where :field.matches =\u003e query\n# ex. :post.matches =\u003e Post.where(:image.exists =\u003e true )\nq.where :field.in_query =\u003e query # alias\n```\n\n#### Excludes Query\nEquivalent to the `$notInQuery` Parse query operation. Useful if you want to retrieve objects where a field contains an object that does not match another query.\n\n```ruby\nq.where :field.excludes =\u003e query\n# ex. :post.excludes =\u003e Post.where(:image.exists =\u003e true\nq.where :field.not_in_query =\u003e query # alias\n```\n\n#### Matches Object Id\nSometimes you want to find rows where a particular Parse object exists. You can do so by passing a the Parse::Object subclass or a Parse::Pointer. In some cases you may only have the \"objectId\" of the record you are looking for. For convenience, you can also use the `id` constraint. This will assume that the name of the field matches a particular Parse class you have defined. Assume the following:\n\n```ruby\n# where this Parse object equals the object in the column `field`.\nq.where :field =\u003e Parse::Pointer(\"Field\", \"someObjectId\")\n# =\u003e \"field\":{\"__type\":\"Pointer\",\"className\":\"Field\",\"objectId\":\"someObjectId\"}}\n\n# alias, shorthand when we infer `:field` maps to `Field` parse class.\nq.where :field.id =\u003e \"someObjectId\"\n# =\u003e \"field\":{\"__type\":\"Pointer\",\"className\":\"Field\",\"objectId\":\"someObjectId\"}}\n\n```\nIt is always important to be thoughtful in naming column names in associations as\nclose to their foreign Parse class names. This enables more expressive syntax while reducing\ncode. The `id` also supports any object or pointer object. These are all equivalent:\n\n```ruby\nq.where :user    =\u003e User.pointer(\"xyx123\")\nq.where :user.id =\u003e \"xyx123\"\nq.where :user.id =\u003e User.pointer(\"xyx123\")\n# All produce\n# =\u003e \"user\":{\"__type\":\"Pointer\",\"className\":\"_User\",\"objectId\":\"xyx123\"}}\n```\n\n##### Additional Examples\n\n```ruby\n\nclass Artist \u003c Parse::Object\n  # as described before\nend\n\nclass Song \u003c Parse::Object\n  belongs_to :artist\nend\n\nartist = Artist.first # get any artist\nartist_id = artist.id # ex. artist.id\n\n# find all songs for this artist object\nSong.all :artist =\u003e artist\n```\n\nIn some cases, you do not have the Parse object, but you have its `objectId`. You can use the objectId in the query as follows:\n\n```ruby\n# shorthand if you are using convention. Will infer class `Artist`\nSong.all :artist.id =\u003e artist_id\n\n# other approaches, same result\nSong.all :artist =\u003e Artist.pointer(artist_id)\nSong.all :artist =\u003e Parse::Pointer.new(\"Artist\", artist_id)\n\n# \"id\" safely pointers and strings for supporting these types of API patterns\ndef find_songs(artist)\n  Song.all :artist.id =\u003e artist\nend\n\n# all ok\nsongs = find_songs artist_id # by a string ObjectId\nsongs = find_songs artist # or by an object or pointer\nsongs = find_songs Artist.pointer(artist_id)\n\n```\n\n### [Geo Queries](https://www.modernistik.com/gems/parse-stack/Parse/Constraint/NearSphereQueryConstraint.html)\nEquivalent to the `$nearSphere` Parse query operation. This is only applicable if the field is of type `GeoPoint`. This will query Parse and return a list of results ordered by distance with the nearest object being first.\n\n```ruby\nq.where :field.near =\u003e geopoint\n\n# example\ngeopoint = Parse::GeoPoint.new(30.0, -20.0)\nPlaceObject.all :location.near =\u003e geopoint\n```\n\n#### Max Distance Constraint\nIf you wish to constrain the geospatial query to a maximum number of __miles__, you can utilize the `max_miles` method on a `Parse::GeoPoint` object. This is equivalent to the `$maxDistanceInMiles` constraint used with `$nearSphere`.\n\n```ruby\nq.where :field.near =\u003e geopoint.max_miles(distance)\n# or provide a triplet includes max miles constraint\nq.where :field.near =\u003e [lat, lng, miles]\n\n# example\ngeopoint = Parse::GeoPoint.new(30.0, -20.0)\nPlaceObject.all :location.near =\u003e geopoint.max_miles(10)\n```\n\nWe will support `$maxDistanceInKilometers` (for kms) and `$maxDistanceInRadians` (for radian angle) in the future.\n\n#### [Bounding Box Constraint](https://www.modernistik.com/gems/parse-stack/Parse/Constraint/WithinGeoBoxQueryConstraint.html)\nEquivalent to the `$within` Parse query operation and `$box` geopoint constraint. The rectangular bounding box is defined by a southwest point as the first parameter, followed by the a northeast point. Please note that Geo box queries that cross the international date lines are not currently supported by Parse.\n\n```ruby\n# GeoPoint bounding box\nq.where :field.within_box =\u003e [soutwestGeoPoint, northeastGeoPoint]\n\n# example\nsw = Parse::GeoPoint.new 32.82, -117.23 # San Diego\nne = Parse::GeoPoint.new 36.12, -115.31 # Las Vegas\n\n# get all PlaceObjects inside this bounding box\nPlaceObject.all :location.within_box =\u003e [sw,ne]\n```\n\n#### [Polygon Area Constraint](https://www.modernistik.com/gems/parse-stack/Parse/Constraint/WithinPolygonQueryConstraint.html)\nEquivalent to the `$geoWithin` Parse query operation and `$polygon` geopoint constraint. The polygon area is described by a list of `Parse::GeoPoint` objects and should contain 3 or more points. This feature is only available in Parse-Server version 2.4.2 and later.\n\n```ruby\n # As many points as you want, minimum 3\n q.where :field.within_polygon =\u003e [geopoint1, geopoint2, geopoint3]\n\n # Polygon for the Bermuda Triangle\n bermuda  = Parse::GeoPoint.new 32.3078000,-64.7504999 # Bermuda\n miami    = Parse::GeoPoint.new 25.7823198,-80.2660226 # Miami, FL\n san_juan = Parse::GeoPoint.new 18.3848232,-66.0933608 # San Juan, PR\n\n # get all sunken ships inside the Bermuda Triangle\n SunkenShip.all :location.within_polygon =\u003e [bermuda, san_juan, miami]\n```\n\n#### [Full Text Search Constraint](https://www.modernistik.com/gems/parse-stack/Parse/Constraint/FullTextSearchQueryConstraint.html)\nEquivalent to the `$text` Parse query operation and `$search` parameter constraint for efficient search capabilities. By creating indexes on one or more columns your strings are turned into tokens for full text search functionality. The `$search` key can take any number of parameters in hash form. *Requires Parse Server 2.5.0 or later*\n\n```ruby\n # Do a full text search on \"anthony\"\n q.where :field.text_search =\u003e \"anthony\"\n\n # perform advance searches\n q.where :field.text_search =\u003e {term: \"anthony\", case_insensitive: true}\n # equivalent\n q.where :field.text_search =\u003e {:$term =\u003e \"anthony\", :$caseInsensitive =\u003e true}\n```\n\nYou may use the following keys for the parameters clause.\n\n| Parameter | Use |\n| :--- | :----- |\n| `$term`               | Specify a field to search (**Required**)|\n| `$language`           | Determines the list of stop words and the rules for tokenizer.|\n| `$caseSensitive`      | Enable or disable case sensitive search.|\n| `$diacriticSensitive` | Enable or disable diacritic sensitive search.|\n\nFor additional details, please see [Query on String Values](https://docs.parseplatform.org/rest/guide/#queries-on-string-values).\n\n### Relational Queries\nEquivalent to the `$relatedTo` Parse query operation. If you want to retrieve objects that are members of a `Relation` field in your Parse class.\n\n```ruby\nq.where :field.related_to =\u003e pointer\nq.where :field.rel =\u003e pointer # alias\n```\n\nIn the example below, imagine you have a `Post` collection that has a Parse relation column `likes`\nwhich has the set of users who have liked a certain post. You would use the `Parse::Users` class to query\nagainst the `post` record of interest against the `likes` column of the `Post` collection.\n\n```ruby\n# assume Post class definition\nclass Post \u003c Parse::Object\n  # Parse relation to Parse::User records who've liked a post\n  has_many :likes, through: :relation, as: :user\nend\n\npost = Post.first\n# find all Users who have liked this post object,\n# where 'likes' is a column on the Post class.\nusers = Parse::User.all :likes.rel =\u003e post\n\n# or use the relation accessor declared in Post\nusers = post.likes.all # same result\n\n# or find posts that a certain user has liked\nuser = Parse::User.first\n# likes is a Parse relation in the Post collection that contains User records\nliked_posts_by_user = Post.all :likes =\u003e user\n```\n\n### Compound Queries\nEquivalent to the `$or` Parse query operation. This is useful if you want to find objects that match several queries. We overload the `|` operator in order to have a clean syntax for joining these `or` operations.\n\n```ruby\nor_query = query1 | query2 | query3 ...\n\n# ex. where wins \u003e 150 || wins \u003c 5\nquery = Player.where(:wins.gt =\u003e 150) | Player.where(:wins.lt =\u003e 5)\nresults = query.results\n```\n\nIf you do not prefer the syntax you may use the `or_where` method to chain multiple `Parse::Query` instances.\n\n```ruby\nquery = Player.where(:wins.gt =\u003e 150)\nquery.or_where(:wins.lt =\u003e 5)\n# where wins \u003e 150 || wins \u003c 5\nresults = query.results\n```\n\n## Query Scopes\nThis feature is a small subset of the [ActiveRecord named scopes](http://guides.rubyonrails.org/active_record_querying.html#scopes) feature. Scoping allows you to specify commonly-used queries which can be referenced as class method calls and are chainable with other scopes. You can use every `Parse::Query` method previously covered such as `where`, `includes` and `limit`.\n\n```ruby\n\nclass Article \u003c Parse::Object\n  property :published, :boolean\n  scope :published, -\u003e { query(published: true) }\nend\n```\n\nThis is the same as defining your own class method for the query.\n\n```ruby\nclass Article \u003c Parse::Object\n  def self.published\n    query(published: true)\n  end\nend\n```\n\nYou can also chain scopes and pass parameters. In addition, boolean and enumerated properties have automatically generated scopes for you to use.\n\n```ruby\n\nclass Article \u003c Parse::Object\n  scope :published, -\u003e { query(published: true) }\n\n  property :comment_count, :integer\n  property :category\n  property :approved, :boolean\n\n  scope :published_and_commented, -\u003e { published.where :comment_count.gt =\u003e 0 }\n  scope :popular_topics, -\u003e(name) { published_and_commented.where category: name }\nend\n\n# simple scope\nArticle.published # =\u003e where published is true\n\n# chained scope\nArticle.published_and_commented # published is true and comment_count \u003e 0\n\n# scope with parameters\nArticle.popular_topic(\"music\") # =\u003e popular music articles\n# equivalent: where(published: true, :comment_count.gt =\u003e 0, category: name)\n\n# automatically generated scope\nArticle.approved(category: \"tour\") # =\u003e where approved: true, category: 'tour'\n\n```\n\nIf you would like to turn off automatic scope generation for property types, set the option `:scope` to false when declaring the property.\n\n## Calling Cloud Code Functions\nYou can call on your defined Cloud Code functions using the `call_function()` method. The result will be `nil` in case of errors or the value of the `result` field in the Parse response.\n\n```ruby\n params = {}\n # use the explicit name of the function\n result = Parse.call_function 'functionName', params\n\n # to get the raw Response object\n response = Parse.call_function 'functionName', params, raw: true\n response.result unless response.error?\n```\n\n## Calling Background Jobs\nYou can trigger background jobs that you have configured in your Parse application as follows.\n\n```ruby\n params = {}\n # use explicit name of the job\n result = Parse.trigger_job :myJobName, params\n\n # to get the raw Response object\n response = Parse.trigger_job :myJobName, params, raw: true\n response.result unless response.error?\n```\n\n## Active Model Callbacks\nAll `Parse::Object` subclasses extend [`ActiveModel::Callbacks`](http://api.rubyonrails.org/classes/ActiveModel/Callbacks.html) for `#save` and `#destroy` operations. You can setup internal hooks for `before` and `after`.\n\n```ruby\n\nclass Song \u003c Parse::Object\n\t# ex. before save callback\n\tbefore_save do\n\t\tself.name = self.name.titleize\n    # make sure global acls are set\n\t\tacl.everyone(true, false) if new?\n\tend\n\n  after_create do\n    puts \"New object successfully saved.\"\n  end\n\nend\n\nsong = Song.new name: \"my title\"\nputs song.name # 'my title'\nsong.save # runs :save callbacks\nputs song.name # 'My Title'\n\n```\n\nThere are also a special `:create` callback. A `before_create` will be called whenever a unsaved object will be saved, and `after_create` will be called when a previously unsaved object successfully saved for the first time.\n\n## Schema Upgrades and Migrations\nYou may change your local Parse ruby classes by adding new properties. To easily propagate the changes to your Parse Server application (MongoDB), you can call `auto_upgrade!` on the class to perform an non-destructive additive schema change. This will create the new columns in Parse for the properties you have defined in your models. Parse Stack will calculate the changes and only modify the tables which need new columns to be added.  This feature does require the use of the master key when configuring the client. *It will NOT destroy columns or data.*\n\n```ruby\n  # auto_upgrade! requires use of master key\n  # upgrade the a class individually\n  Song.auto_upgrade!\n\n  # upgrade all classes for the default client connection.\n  Parse.auto_upgrade!\n\n```\n\n## Push Notifications\nPush notifications are implemented through the `Parse::Push` class. To send push notifications through the REST API, you must enable `REST push enabled?` option in the `Push Notification Settings` section of the `Settings` page in your Parse application. Push notifications targeting uses the Installation Parse class to determine which devices receive the notification. You can provide any query constraint, similar to using `Parse::Query`, in order to target the specific set of devices you want given the columns you have configured in your `Installation` class. The `Parse::Push` class supports many other options not listed here.\n\n```ruby\n\n push = Parse::Push.new\n push.send( \"Hello World!\") # to everyone\n\n # simple channel push\n push = Parse::Push.new\n push.channels = [\"addicted2salsa\"]\n push.send \"You are subscribed to Addicted2Salsa!\"\n\n # advanced targeting\n push = Parse::Push.new( {..where query constraints..} )\n # or use `where()`\n push.where :device_type.in =\u003e ['ios','android'], :location.near =\u003e some_geopoint\n push.alert = \"Hello World!\"\n push.sound = \"soundfile.caf\"\n\n  # additional payload data\n push.data = { uri: \"app://deep_link_path\" }\n\n # Send the push\n push.send\n\n```\n\n## Cloud Code Webhooks\nParse Parse allows you to receive Cloud Code webhooks on your own hosted server. The `Parse::Webhooks` class is a lightweight Rack application that routes incoming Cloud Code webhook requests and payloads to locally registered handlers. The payloads are `Parse::Webhooks::Payload` type of objects that represent that data that Parse sends webhook handlers. You can register any of the Cloud Code webhook trigger hooks (`beforeSave`, `afterSave`, `beforeDelete`, `afterDelete`) and function hooks.\n\n### Cloud Code Functions\nYou can use the `route()` method to register handler blocks. The last value returned by the block will be returned back to the client in a success response. If `error!(value)` is called inside the block, we will return the correct Parse error response with the value you provided.\n\n```ruby\n# Register handling the 'helloWorld' function.\nParse::Webhooks.route(:function, :helloWorld) do\n  #  use the Parse::Webhooks::Payload instance methods in this block\n  name = params['name'].to_s #function params\n  puts \"CloudCode Webhook helloWorld called in Ruby!\"\n  # will return proper error response\n  # error!(\"Missing argument 'name'.\") unless name.present?\n\n  name.present? ? \"Hello #{name}!\" : \"Hello World!\"\nend\n\n# Advanced: you can register handlers through classes if you prefer\n# Parse::Webhooks.route :function, :myFunc, MyClass.method(:my_func)\n```\n\nIf you have registered this webhook (see instructions below), you should be able to test it out by running curl using the command below.\n\n```bash\ncurl -X POST \\\n  -H \"X-Parse-Application-Id: ${APPLICATION_ID}\" \\\n  -H \"X-Parse-REST-API-Key: ${REST_API_KEY}\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{}' \\\n  https://localhost:1337/parse/functions/helloWorld\n```\n\nIf you are creating `Parse::Object` subclasses, you may also register them there to keep common code and functionality centralized.\n\n```ruby\nclass Song \u003c Parse::Object\n\n  webhook :function, :mySongFunction do\n    the_user = user # available if a Parse user made the call\n    str = params[\"str\"]\n\n    # ... get the list of matching songs the user has access to.\n    results = Songs.all(:name.like =\u003e /#{str}/, :session =\u003e the_user)\n    # Helper method for logging\n    wlog \"Found #{results.count} for #{the_user.username}\"\n\n    results\n  end\n\nend\n\n```\n\nYou may optionally, register these functions outside of classes (recommended).\n\n```ruby\nParse::Webhooks.route :function, :mySongFunction do\n  # .. do stuff ..\n  str = params[\"str\"]\n  results = Songs.all(:name.like =\u003e /#{str}/, :session =\u003e user)\n  results\nend\n```\n\n### Cloud Code Triggers\nYou can register webhooks to handle the different object triggers: `:before_save`, `:after_save`, `:before_delete` and `:after_delete`. The `payload` object, which is an instance of `Parse::Webhooks::Payload`, contains several properties that represent the payload. One of the most important ones is `parse_object`, which will provide you with the instance of your specific Parse object. In `:before_save` triggers, this object already contains dirty tracking information of what has been changed.\n\n```ruby\n  # recommended way\n  class Artist \u003c Parse::Object\n    # ... properties ...\n\n    # setup after save for Artist\n    webhook :after_save do\n      puts \"User: #{user.username}\" if user.present? # Parse::User\n      artist = parse_object # Artist\n      # no need for return in after save\n    end\n\n  end\n\n  # or the explicit way\n  Parse::Webhooks.route :after_save, :Artist do\n    puts \"User: #{user.username}\" if user.present? # Parse::User\n    artist = parse_object # Artist\n    # no need for return in after save\n  end\n```\n\nFor any `after_*` hook, return values are not needed since Parse does not utilize them. You may also register as many `after_save` or `after_delete` handlers as you prefer, all of them will be called.\n\n`before_save` and `before_delete` hooks have special functionality. When the `error!` method is called by the provided block, the framework will return the correct error response to Parse with value provided. Returning an error will prevent Parse from saving the object in the case of `before_save` and will prevent Parse from deleting the object when in a `before_delete`. In addition, for a `before_save`, the last value returned by the block will be the value returned in the success response. If the block returns nil or an `empty?` value, it will return `true` as the default response. You can also return a JSON object in a hash format to override the values that will be saved. However, we recommend modifying the `parse_object` provided since it has dirty tracking, and then returning that same object. This will automatically call your model specific `before_save` callbacks and send the proper payload back to Parse. For more details, see [Cloud Code BeforeSave Webhooks](http://docs.parseplatform.org/cloudcode/guide/#beforesave-triggers)\n\n```ruby\n# recommended way\nclass Artist \u003c Parse::Object\n  property :name\n  property :location, :geopoint\n\n  # setup after save for Artist\n  webhook :before_save do\n    the_user = user # Parse::User\n    artist = parse_object # Artist\n    # artist object will have dirty tracking information\n\n    artist.new? # true if this is a new object\n\n    # default San Diego\n    artist.location ||= Parse::GeoPoint.new(32.82, -117.23)\n\n    # raise to fail the save\n    error!(\"Name cannot be empty\") if artist.name.blank?\n\n    if artist.name_changed?\n      wlog \"The artist name changed!\"\n      # .. do something if `name` has changed\n    end\n\n    # *important* returns a special hash of changed values\n    artist\n  end\n\n  webhook :before_delete do\n    # prevent deleting Artist records\n    error!(\"You can't delete an Artist\")\n  end\n\nend\n\n```\n\n### Mounting Webhooks Application\nThe app can be mounted like any regular Rack-based application.\n\n```ruby\n  # Rack (add this to config.ru)\n  map \"/webhooks\" do\n    run Parse::Webhooks\n  end\n\n  # or in Padrino (add this to apps.rb)\n  Padrino.mount('Parse::Webhooks', :cascade =\u003e true).to('/webhooks')\n\n  # or in Rails (add this in routes.rb)\n  Rails.application.routes.draw do\n    mount Parse::Webhooks, :at =\u003e '/webhooks'\n  end\n```\n\n### Register Webhooks\nOnce you have locally setup all your trigger and function routes, you can write a small rake task to automatically register these hooks with your Parse application. To do this, you can configure a `HOOKS_URL` variable to be used as the endpoint. If you are using a service like Heroku, this would be the name of the heroku app url followed by your configured mount point.\n\n```ruby\n# ex. https://12345678.ngrok.com/webhooks\nHOOKS_URL = ENV[\"HOOKS_URL\"]\n\n# Register locally setup handlers with Parse\ntask :register_hooks do\n  # Parse.setup(....) if needed\n  Parse::Webhooks.register_functions! HOOKS_URL\n  Parse::Webhooks.register_triggers! HOOKS_URL\nend\n\n# Remove all webhooks!\ntask :remove_hooks do\n  # Parse.setup(....) if needed\n  Parse::Webhooks.remove_all_functions!\n  Parse::Webhooks.remove_all_triggers!\nend\n\n```\n\nHowever, we have predefined a few rake tasks you can use in your application. Just require `parse/stack/tasks` in your `Rakefile` and call `Parse::Stack.load_tasks`. This is useful for web frameworks like `Padrino`. Note that if you are using Parse-Stack with Rails, this is automatically done for you through the Railtie.\n\n```ruby\n  # Add to your Rakefile (if not using Rails)\n  require 'parse/stack/tasks' # add this line\n  Parse::Stack.load_tasks # add this line\n```\n\nThen you can see the tasks available by typing `rake -T`.\n\n## Parse REST API Client\nWhile in most cases you do not have to work with `Parse::Client` directly, you can still utilize it for any raw requests that are not supported by the framework. We provide support for most of the [Parse REST API](http://docs.parseplatform.org/rest/guide/#quick-reference) endpoints as helper methods, however you can use the `request()` method to make your own API requests. Parse::Client will handle header authentication, request/response generation and caching.\n\n```ruby\nclient = Parse::Client.new(application_id: \u003cstring\u003e, api_key: \u003cstring\u003e) do |conn|\n\t# .. optional: configure additional middleware\nend\n\n # Use API helper methods...\n client.config\n client.create_object \"Artist\", {name: \"Hector Lavoe\"}\n client.call_function \"myCloudFunction\", { key: \"value\"}\n\n # or use low-level request method\n client.request :get, \"/1/users\", query: {} , headers: {}\n client.request :post, \"/1/users/\u003cobjectId\u003e\", body: {} , headers: {}\n\n```\n\nIf you are already have setup a client that is being used by your defined models, you can access the current client with the following API:\n\n```ruby\n  # current Parse::Client used by this model\n  client = Song.client\n\n  # you can also have multiple clients\n  client = Parse::Client.client #default client session\n  client = Parse::Client.client(:other_session)\n\n```\n\n##### Options\n- **app_id**: Your Parse application identifier\u0010.\n- **api_key**: Your REST API key corresponding to the provided `application_id`.\n- **master_key**: The master secret key for the application. If this is provided, `api_key` may be unnecessary.\n- **logging**: A boolean value to add additional logging messages.\n- **cache**: A [Moneta](https://github.com/minad/moneta) cache store that can be used to cache API requests. We recommend use a cache store that supports native expires like [Redis](http://redis.io). For more information see `Parse::Middleware::Caching`. Disabled by default.\n- **expires**: When used with the `cache` option, sets the expiration time of cached API responses. The default is 3 seconds.\n- **adapter**: The connection adapter to use. Defaults to `Faraday.default_adapter`.\n\n### Request Caching\nFor high traffic applications that may be performing several server tasks on similar objects, you may utilize request caching. Caching is provided by a the `Parse::Middleware::Caching` class which utilizes a [Moneta store](https://github.com/minad/moneta) object to cache GET url requests that have allowable status codes (ex. HTTP 200, etc). The cache entry for the url will be removed when it is either considered expired (based on the `expires` option) or if a non-GET request is made with the same url. Using this feature appropriately can dramatically reduce your API request usage.\n\n```ruby\nstore = Moneta.new :Redis, url: 'redis://localhost:6379'\n # use a Redis cache store with an automatic expire of 10 seconds.\nParse.setup(cache: store, expires: 10, ...)\n\nuser = Parse::User.first # request made\nsame_user = Parse::User.first # cached result\n\n# you may clear the cache at any time\n# clear the cache for the default session\nParse::Client.client.clear_cache!\n\n# or through the client accessor of a model\nSong.client.clear_cache!\n```\n\nYou can always access the default shared cache through `Parse.cache` and utilize it\nfor other purposes in your application:\n\n```ruby\n# Access the cache instance for other uses\nParse.cache[\"key\"] = \"value\"\nParse.cache[\"key\"] # =\u003e \"value\"\n\n# or with Parse queries and objects\nParse.cache.fetch(\"all:records\") do |key|\n  results = Song.all # or other complex query or operation\n  # store it in the cache, but expires in 30 seconds\n  Parse.cache.store(key, results, expires: 30)\nend\n\n```\n\n## Contributing\n\nBug reports and pull requests are welcome on GitHub at [https://github.com/modernistik/parse-stack](https://github.com/modernistik/parse-stack).\n\n## License\n\nThe gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frubyonworld%2Fparse-stack","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frubyonworld%2Fparse-stack","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frubyonworld%2Fparse-stack/lists"}