Class: Parse::Object
- Extended by:
- Core::Describe, Core::Indexing, Core::Querying, Core::Schema, Core::SearchIndexing, Core::VectorSearchable
- Includes:
- Agent::MetadataDSL, Associations::BelongsTo, Associations::HasMany, Associations::HasOne, Core::Actions, Core::EmbedManaged, Core::EnhancedChangeTracking, Core::Fetching, Core::FieldGuards, Core::ParseReference, ValidationCallbackOnSupport, Properties
- Defined in:
- lib/parse/model/object.rb,
lib/parse/console.rb,
lib/parse/webhooks.rb
Overview
This is the core class for all app specific Parse table subclasses. This class in herits from Parse::Pointer since an Object is a Parse::Pointer with additional fields, at a minimum, created_at, updated_at and ACLs. This class also handles all the relational types of associations in a Parse application and handles the main CRUD operations.
As the parent class to all custom subclasses, this class provides the default property schema:
class Parse::Object
# All subclasses will inherit these properties by default.
# the objectId column of a record.
property :id, :string, field: :objectId
# The the last updated date for a record (Parse::Date)
property :updated_at, :date
# The original creation date of a record (Parse::Date)
property :created_at, :date
# The Parse::ACL field
property :acl, :acl, field: :ACL
end
Most Pointers and Object subclasses are treated the same. Therefore, defining a class Artist < Parse::Object
that only has id set, will be treated as a pointer. Therefore a Parse::Object can be in a "pointer" state
based on the data that it contains. Becasue of this, it is possible to take a Artist instance
(in this example), that is in a pointer state, and fetch the rest of the data for that particular
record without having to create a new object. Doing so would now mark it as not being a pointer anymore.
This is important to the understanding on how relations and properties are handled.
The implementation of this class is large and has been broken up into several modules.
Properties:
All columns in a Parse object are considered a type of property (ex. string, numbers, arrays, etc) except in two cases - Pointers and Relations. For a detailed discussion of properties, see The Defining Properties section.
Associations:
Parse 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.
Direct Known Subclasses
Audience, Installation, JobSchedule, JobStatus, Product, PushStatus, Role, Session, User
Defined Under Namespace
Modules: ValidationCallbackOnSupport
Constant Summary collapse
- VALID_ACL_POLICIES =
Valid ACL policies that can be passed to acl_policy.
[:public, :public_read, :private, :owner_else_public, :owner_else_private, :owner_but_public_read].freeze
- BUILTIN_PARSE_CLASS_NAMES =
SDK-provided Parse model class names that the policy resolver and init-time default-ACL stamp both skip. Parse Server applies its own per-class defaults for these classes when the save body omits the
ACLfield — most importantly,_Usergets{"<user-id>": R/W, "*": R}so the newly created user can edit their own profile. Stamping any ACL from the SDK side (even{}) overrides those server-side defaults and is almost always wrong. %w[ Parse::User Parse::Installation Parse::Session Parse::Role Parse::Product Parse::PushStatus Parse::Audience Parse::JobStatus Parse::JobSchedule ].freeze
- IDENTIFICATION_FIELDS =
Core identification fields that are always included in serialization unless strict: true is specified
%w[id objectId __type className].freeze
Constants included from Core::Schema
Core::Schema::DEFAULT_PUBLIC_CLP, Core::Schema::SCHEMA_READONLY_CLASSES
Constants included from Core::Describe
Core::Describe::ALL_SECTIONS, Core::Describe::CORE_FIELD_KEYS, Core::Describe::LOCAL_SECTIONS, Core::Describe::NETWORK_SECTIONS
Constants included from Core::Indexing
Core::Indexing::MAX_INDEXES_PER_COLLECTION, Core::Indexing::PARSE_MANAGED_ARRAY_FIELDS, Core::Indexing::SENSITIVE_FIELDS
Constants included from Core::SearchIndexing
Core::SearchIndexing::ALLOWED_INDEX_TYPES, Core::SearchIndexing::INDEX_NAME_PATTERN
Constants included from Core::Fetching
Core::Fetching::NON_SERIALIZABLE_IVARS
Constants included from Core::EmbedManaged
Core::EmbedManaged::WRITER_KEY
Constants included from Core::ParseReference
Core::ParseReference::OBJECT_ID_LENGTH, Core::ParseReference::SEPARATOR
Constants included from Core::FieldGuards
Core::FieldGuards::GUARD_MODES
Constants included from Properties
Properties::BASE, Properties::BASE_FIELD_MAP, Properties::BASE_KEYS, Properties::CORE_FIELDS, Properties::DELETE_OP, Properties::PROTECTED_INITIALIZE_KEYS, Properties::PROTECTED_MASS_ASSIGNMENT_KEYS, Properties::TYPES
Constants inherited from Pointer
Pointer::ATTRIBUTES, Pointer::OBJECT_ID_FORMAT
Constants inherited from Model
Model::CLASS_AUDIENCE, Model::CLASS_INSTALLATION, Model::CLASS_JOB_SCHEDULE, Model::CLASS_JOB_STATUS, Model::CLASS_PRODUCT, Model::CLASS_PUSH_STATUS, Model::CLASS_ROLE, Model::CLASS_SCHEMA, Model::CLASS_SESSION, Model::CLASS_USER, Model::ID, Model::KEY_CLASS_NAME, Model::KEY_CREATED_AT, Model::KEY_OBJECT_ID, Model::KEY_UPDATED_AT, Model::OBJECT_ID, Model::TYPE_ACL, Model::TYPE_BYTES, Model::TYPE_DATE, Model::TYPE_FIELD, Model::TYPE_FILE, Model::TYPE_GEOPOINT, Model::TYPE_NUMBER, Model::TYPE_OBJECT, Model::TYPE_POINTER, Model::TYPE_POLYGON, Model::TYPE_RELATION
Class Attribute Summary collapse
-
.default_acl_private ⇒ Boolean
When set to true, new instances of this class will have a private ACL (no public access, master key only) instead of the default public read/write.
-
.parse_class(remoteName = nil) ⇒ String
The class method to override the implicitly assumed Parse collection name in your Parse database.
-
.suppress_permissive_acl_warning ⇒ Boolean
When set on
Parse::Objectitself, suppresses the one-time per-class warning emitted when a class's effective Object.acl_policy_setting is:publicor:owner_else_public.
Instance Attribute Summary collapse
-
#acl ⇒ ACL
The access control list (permissions) object for this record.
-
#created_at ⇒ Date
readonly
The created_at date of the record in UTC Zulu iso 8601 with 3 millisecond format.
-
#id ⇒ String
The value of Parse "objectId" field.
-
#updated_at ⇒ Date
readonly
The updated_at date of the record in UTC Zulu iso 8601 with 3 millisecond format.
Class-Level Permissions (CLP) collapse
-
.class_permissions ⇒ Parse::CLP
(also: clp)
The Class-Level Permissions for this model.
-
.describe_access ⇒ Hash
Introspect the locally-configured access surface for this class.
-
.fetch_clp(client: nil) ⇒ Parse::CLP
(also: fetch_class_permissions)
Fetch the current CLP from the Parse Server for this class.
-
.master_only_class! ⇒ void
Lock every CLP operation to master-key access only.
-
.protect_fields(pattern, fields) ⇒ Object
(also: set_protected_fields)
Define protected fields that should be hidden from certain users/roles.
-
.set_class_access(**ops_to_access) ⇒ void
Set CLP for multiple operations in one call, choosing a coarse access mode per operation.
-
.set_clp(operation, public: nil, roles: [], users: [], pointer_fields: [], requires_authentication: false) ⇒ Object
(also: set_class_permission)
Set a class-level permission for a specific operation.
-
.set_default_clp(public: nil, roles: [], requires_authentication: false) ⇒ Object
Set default permissions for all CLP operations at once.
-
.set_read_user_fields(*fields) ⇒ Object
Set pointer-permission fields for read access.
-
.set_write_user_fields(*fields) ⇒ Object
Set pointer-permission fields for write access.
-
.unlistable_class! ⇒ void
Restrict
findandcountto master-key only, leaving the other operations (get,create,update,delete,addField) at their current settings. -
.update_clp!(client: nil, replace: false) ⇒ Parse::Response
(also: update_class_permissions!)
Update the CLP on the Parse Server for this class.
Field Filtering (CLP) collapse
-
.filter_results_for_user(objects, user, roles: [], authenticated: nil, clp: nil) ⇒ Array<Hash>
Filter an array of Parse objects or hashes for a user.
-
.roles_for_user(user) ⇒ Array<String>
Fetch a user's roles for use with field filtering.
-
#filter_for_user(user, roles: [], authenticated: nil, clp: nil) ⇒ Hash
Filter this object's fields based on Class-Level Permissions for a user.
Class Method Summary collapse
-
.acl_owner_field ⇒ Symbol?
The name of the property/belongs_to designating the owner user for
:owner_else_*ACL policies. -
.acl_policy(policy, owner: nil) ⇒ Object
Declarative ACL policy applied to newly-created instances of this class.
-
.acl_policy_setting ⇒ Symbol
The effective ACL policy for this class.
-
.build(json, table = nil, fetched_keys: nil, nested_fetched_keys: nil) ⇒ Parse::Object
Method used for decoding JSON objects into their corresponding Object subclasses.
-
.default_acls ⇒ Parse::ACL
The set of default ACLs to be applied on newly created instances of this class.
-
.pointer(id) ⇒ Parse::Pointer
Helper method to create a Parse::Pointer object for a given id.
-
.private_acl! ⇒ Object
Convenience method to set default ACL to private (no public access).
-
.set_default_acl(id, read: false, write: false, role: false) ⇒ Object
A method to set default ACLs to be applied for newly created instances of this class.
-
.wait_for(**kwargs, &block) ⇒ Object
Block until the first row matching Core::Querying#where (and an optional predicate block) arrives via LiveQuery.
-
.watch(**kwargs, &block) ⇒ Object
Tail this class as LiveQuery events arrive — blocking, Ctrl-C to stop.
-
.webhook(type, &block) { ... } ⇒ OpenStruct
Register a webhook trigger or function for this subclass.
-
.webhook_function(functionName, &block) { ... } ⇒ OpenStruct
Register a webhook function for this subclass.
Instance Method Summary collapse
-
#[](key) ⇒ Object
Access the value for a defined property through hash accessor.
-
#[]=(key, value) ⇒ Object
Set the value for a specific property through a hash accessor.
- #__type ⇒ Model::TYPE_OBJECT
-
#_resolve_acl_owner_id(owner) ⇒ Object
private
Resolves an
as:value or owner-field pointer to an objectId string. -
#_resolve_default_acl ⇒ Object
private
Save-time resolver for the declarative Object.acl_policy default ACL.
-
#acl_changed? ⇒ Boolean
Override acl_changed? to compare actual ACL content, not just object references.
-
#acl_was ⇒ Parse::ACL
Override acl_was to return the captured snapshot instead of the reference stored by ActiveModel's dirty tracking.
-
#acl_will_change! ⇒ Object
private
Override acl_will_change! to capture a snapshot of the ACL before modification.
-
#after_create { ... } ⇒ Object
A callback called after the object has been created.
-
#after_destroy { ... } ⇒ Object
A callback called after the object has been successfully deleted.
-
#after_save { ... } ⇒ Object
A callback called after the object has been successfully saved.
-
#after_update { ... } ⇒ Object
A callback called after the object has been updated.
-
#after_validation { ... } ⇒ Object
A callback called after validations are run.
-
#apply_defaults! ⇒ Array
force apply default values for any properties defined with default values.
-
#around_create { ... } ⇒ Object
A callback called around object creation.
-
#around_destroy { ... } ⇒ Object
A callback called around object destruction.
-
#around_save { ... } ⇒ Object
A callback called around object save.
-
#around_update { ... } ⇒ Object
A callback called around object update.
-
#around_validation { ... } ⇒ Object
A callback called around validations.
-
#as_json(opts = nil) ⇒ Hash
A json-hash representing this object.
-
#autofetch_disabled? ⇒ Boolean
Returns whether autofetch is disabled for this instance.
-
#before_create { ... } ⇒ Object
A callback called before the object has been created.
-
#before_destroy { ... } ⇒ Object
A callback called before the object is about to be deleted.
-
#before_save { ... } ⇒ Object
A callback called before the object is saved.
-
#before_update { ... } ⇒ Object
A callback called before the object is updated (not on create).
-
#before_validation { ... } ⇒ Object
A callback called before validations are run.
-
#changed ⇒ Array<String>
Override changed to filter out ACL when its content hasn't actually changed.
-
#changed? ⇒ Boolean
Override changed? to use our filtered changed list.
-
#clear_attribute_change!(atts) ⇒ Object
clear all change and dirty tracking information.
-
#clear_changes! ⇒ Object
clears all dirty tracking information.
-
#clear_partial_fetch_state! ⇒ void
Clears all partial fetch tracking state.
-
#disable_autofetch! ⇒ void
Disables autofetch for this object instance.
-
#enable_autofetch! ⇒ void
Enables autofetch for this object instance (default behavior).
-
#existed? ⇒ Boolean
Existed returns true if the object had existed before its last save operation.
-
#fetched? ⇒ Boolean
Returns whether this object has been fetched from the server (fully or partially).
-
#fetched_keys ⇒ Array<Symbol>
Returns the array of keys that were fetched for this object.
-
#fetched_keys=(keys) ⇒ Array
Sets the fetched keys for this object.
-
#field_was_fetched?(key) ⇒ Boolean
Returns whether a specific field was fetched for this object.
-
#fully_fetched? ⇒ Boolean
Returns whether this object is fully fetched with all fields available.
-
#has?(key) ⇒ Boolean
Check if a field has a value (is present and not nil).
-
#has_selective_keys? ⇒ Boolean
private
Returns whether this object was fetched with specific keys (selective fetch).
-
#initialize(opts = {}) ⇒ Parse::Object
constructor
The main constructor for subclasses.
-
#keys ⇒ Array<String>
Returns an array of property names (keys) for this Parse::Object.
-
#nested_fetched_keys ⇒ Hash
Returns the nested fetched keys map for building nested objects.
-
#nested_fetched_keys=(keys_map) ⇒ Hash
Sets the nested fetched keys map for building nested objects.
-
#nested_keys_for(field_name) ⇒ Array?
Gets the fetched keys for a specific nested field.
-
#new? ⇒ Boolean
An object is considered new until it has been successfully persisted to the server.
-
#parse_class ⇒ String
(also: #className)
The Parse class for this object.
-
#partially_fetched? ⇒ Boolean
Returns whether this object was fetched with specific keys (partial/selective fetch).
-
#persisted? ⇒ Boolean
Determines if this object has been saved to the Parse database.
-
#pretty ⇒ String
A pretty-formatted JSON string.
-
#reload!(**opts) ⇒ Object
Force reload from the database and replace any local fields with data from the persistent store.
-
#rollback! ⇒ Object
Locally restores the previous state of the object and clears all dirty tracking information.
-
#run_after_create_callbacks ⇒ Boolean
Run after_create callbacks for this object.
-
#run_after_delete_callbacks ⇒ Boolean
Run after_destroy callbacks for this object.
-
#run_after_save_callbacks ⇒ Boolean
Run after_save callbacks for this object.
-
#schema ⇒ Hash
The schema structure for this Parse collection from the server.
-
#search_highlights ⇒ Hash?
Atlas Search highlights blob.
-
#search_score ⇒ Float?
Atlas Search relevance score.
-
#twin ⇒ Parse::Object
This method creates a new object of the same instance type with a copy of all the properties of the current instance.
-
#updates(include_all = false) ⇒ Hash
Returns a hash of all the changes that have been made to the object.
-
#valid?(context = nil) ⇒ Boolean
Override valid? to run validation callbacks.
-
#validate! ⇒ self
Overrides ActiveModel::Validations#validate! instance method.
-
#vector_score ⇒ Float?
Search/vector-search result accessors.
Methods included from Core::Querying
all, all_as, count, count_distinct, cursor, distinct, each, find, find_cached, first, first_as, last_updated, latest, literal_where, newest, oldest, query, scope, subscribe
Methods included from Core::Schema
_default_class_level_permissions_for_upgrade, auto_upgrade!, create_schema, fetch_schema, reset_clp!, update_schema
Methods included from Core::Describe
Methods included from Core::Indexing
apply_indexes!, indexes_plan, mongo_geo_index, mongo_index, mongo_index_declarations, mongo_relation_index
Methods included from Core::SearchIndexing
apply_search_indexes!, mongo_search_index, mongo_search_index_declarations, search_indexes_plan
Methods included from Core::VectorSearchable
Methods included from Agent::MetadataDSL
#agent_description, #agent_methods, included, #property_descriptions, #property_enum_descriptions
Methods included from Core::Actions
#_deleted?, #change_requests, #changes_applied!, #changes_payload, #create, #destroy, #destroy_request, #op_add!, #op_add_relation!, #op_add_unique!, #op_destroy!, #op_increment!, #op_remove!, #op_remove_relation!, #operate_field!, #prepare_save!, #relation_change_operations, #save, #save!, #set_attributes!, #update, #update!, #update_relations, #uri_path
Methods included from Core::Fetching
#autofetch!, #fetch, #fetch!, #fetch_cache!, #fetch_json, #fetch_object, #prepare_for_dirty_tracking!
Methods included from Associations::HasMany
has_many, #relation_changes?, #relation_updates, #relations
Methods included from Associations::BelongsTo
Methods included from Associations::HasOne
Methods included from Core::ParseReference
format, generate_object_id, parse
Methods included from Core::FieldGuards
Methods included from Core::EnhancedChangeTracking
Methods included from Properties
#apply_attributes!, #attribute_changes?, #attribute_updates, #attributes, #attributes=, #field_map, #fields, #format_operation, #format_value
Methods inherited from Pointer
#==, #attributes, #fetch, #fetch_cache!, #fetch_json, #fetch_object, #hash, #json_hash, #method_missing, #pointer, #pointer?, #present?, #respond_to_missing?, #sig
Methods inherited from Model
Methods included from Client::Connectable
Constructor Details
#new(id) ⇒ Parse::Object #new(hash = {}) ⇒ Parse::Object
Should only be called with Parse::Object subclasses.
The main constructor for subclasses. It can take different parameter types
including a String and a JSON hash. Assume a Post class that inherits
from Parse::Object:
1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 |
# File 'lib/parse/model/object.rb', line 1316 def initialize(opts = {}) # Trusted hydration is signalled by the +@_trusted_init+ instance # variable rather than by a +trusted:+ keyword argument. Using a # keyword would break subclasses that override +initialize(*args)+ # and call +super+ — Ruby 3 keyword-arg semantics would convert the # kwarg into a positional Hash through the variadic +*args+ splat # and the subsequent +super+ would arrive at this method with two # positional args. The internal hydration paths # ({Parse::Object.build}, {Parse::Pointer} autofetch, # {Parse::User#session}) +allocate+ the object, set the ivar, then # invoke +initialize+ so subclass overrides still fire and pick up # the trust signal here. trusted = @_trusted_init == true @_trusted_init = nil acl_owner_override = nil if opts.is_a?(String) #then it's the objectId @id = opts.to_s elsif opts.is_a?(Hash) # Pop the `:as` option (also accepts string key) before applying # attributes so it is not mistaken for a model property. This holds # the caller-supplied owner user for save-time ACL resolution. acl_owner_override = opts.delete(:as) || opts.delete("as") #if the objectId is provided we will consider the object pristine #and not track dirty items dirty_track = opts[Parse::Model::OBJECT_ID] || opts[:objectId] || opts[:id] # Always filter the narrow PROTECTED_INITIALIZE_KEYS set unless # the caller is a trusted hydration path. Decoupled from # dirty_track so an objectId-bearing hash from a controller, # JSON params, or cache rehydrator cannot mass-assign # sessionToken / _rperm / _wperm / _hashed_password / authData / # roles. The narrow list deliberately allows createdAt / # updatedAt / className / __type through so the legitimate # +Klass.new("objectId" => id, "createdAt" => ts, …)+ # cache-rehydrate pattern keeps working. apply_attributes!(opts, dirty_track: !dirty_track, filter_protected: !trusted, protected_set: Parse::Properties::PROTECTED_INITIALIZE_KEYS) end # If the caller did not set an ACL via opts, stamp the class default ACL # (the policy's fallback half) so `obj.acl` reads sensibly pre-save. # We mark the object as "ACL-pristine": the save-time resolver # (#_resolve_default_acl) may upgrade this to an owner-only ACL if an # `as:` user or owner field is resolvable. Any explicit caller change # via `acl=` flips pristine off via #acl_will_change!. # # Built-in Parse classes (User, Installation, Session, Role, …) are # exempt: the SDK leaves their `acl` untouched (nil) so the save body # omits the `ACL` field and Parse Server applies its own per-class # defaults. Most importantly this lets `_User` get the standard # self-write-plus-public-read ACL on signup; stamping any value from # the SDK side (even `{}`) overrides that and locks the new user out # of editing their own profile without the master key. acl_was_user_supplied = !self.acl.nil? unless self.class.builtin_acl_default_active? self.acl = self.class.default_acls.as_json if self.acl.nil? end @_acl_pristine = !acl_was_user_supplied @_acl_owner_override = acl_owner_override # One-time per-class permissive-default warning. Fires only when the # effective policy is :public or :owner_else_public. self.class._warn_permissive_acl_default_once # do not apply defaults on a pointer because it will stop it from being # a pointer and will cause its field to be autofetched (for sync). # Note: apply_defaults! already skips unfetched fields on selectively fetched objects. if !pointer? apply_defaults! end # clear changes AFTER applying defaults, so fields set by defaults # are not marked dirty when fetching with specific keys clear_changes! if @id.present? #then it was an import # do not call super since it is Pointer subclass end |
Dynamic Method Handling
This class handles dynamic methods through the method_missing method in the class Parse::Pointer
Class Attribute Details
.default_acl_private ⇒ Boolean
When set to true, new instances of this class will have a private ACL (no public access, master key only) instead of the default public read/write.
349 350 351 |
# File 'lib/parse/model/object.rb', line 349 def default_acl_private @default_acl_private end |
.parse_class(remoteName = nil) ⇒ String
The class method to override the implicitly assumed Parse collection name in your Parse database. The default Parse collection name is the singular form of the ruby Parse::Object subclass name. The Parse class value should match to the corresponding remote table in your database in order to properly store records and perform queries.
379 380 381 382 383 |
# File 'lib/parse/model/object.rb', line 379 def parse_class(remoteName = nil) @parse_class ||= model_name.name @parse_class = remoteName.to_s unless remoteName.nil? @parse_class end |
.suppress_permissive_acl_warning ⇒ Boolean
When set on Parse::Object itself, suppresses the one-time per-class
warning emitted when a class's effective acl_policy_setting is
:public or :owner_else_public. Useful in test suites or apps that
have deliberately reviewed and accepted permissive defaults.
Defaults to true when ENV["PARSE_SUPPRESS_PERMISSIVE_ACL_WARNING"]
is set to a truthy value (1, true, yes).
329 |
# File 'lib/parse/model/object.rb', line 329 attr_writer :suppress_permissive_acl_warning |
Instance Attribute Details
#acl ⇒ ACL
Returns the access control list (permissions) object for this record.
1813 |
# File 'lib/parse/model/object.rb', line 1813 property :acl, :acl, field: :ACL |
#created_at ⇒ Date (readonly)
Returns the created_at date of the record in UTC Zulu iso 8601 with 3 millisecond format.
1805 |
# File 'lib/parse/model/object.rb', line 1805 property :created_at, :date |
#id ⇒ String
Returns the value of Parse "objectId" field.
1801 |
# File 'lib/parse/model/object.rb', line 1801 property :id, field: :objectId |
#updated_at ⇒ Date (readonly)
Returns the updated_at date of the record in UTC Zulu iso 8601 with 3 millisecond format.
1809 |
# File 'lib/parse/model/object.rb', line 1809 property :updated_at, :date |
Class Method Details
.acl_owner_field ⇒ Symbol?
The name of the property/belongs_to designating the owner user for
:owner_else_* ACL policies. Inherited from the superclass when not
explicitly declared via acl_policy.
571 572 573 574 575 576 577 578 |
# File 'lib/parse/model/object.rb', line 571 def acl_owner_field return @acl_owner_field if defined?(@acl_owner_field) && @acl_owner_field if self != Parse::Object && superclass.respond_to?(:acl_owner_field) superclass.acl_owner_field else nil end end |
.acl_policy(policy, owner: nil) ⇒ Object
Declarative ACL policy applied to newly-created instances of this class.
The policy is resolved at save time so that explicit ACL changes by the
caller (obj.acl = …, as: kwarg, owner-field assignment after .new)
always take precedence over the default.
Resolution order at save (only when caller has not overridden):
- Explicit
as: userpassed at construction → owner R/W only - Owner pointer resolved from the declared
owner:field → owner R/W only - The else-half of the policy:
:public→ public R/W,:private→ master-key only
498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 |
# File 'lib/parse/model/object.rb', line 498 def acl_policy(policy, owner: nil) unless VALID_ACL_POLICIES.include?(policy) raise ArgumentError, "Invalid acl_policy #{policy.inspect}; must be one of #{VALID_ACL_POLICIES.inspect}" end # Symmetric to the guard in set_default_acl: pick one API per class. if defined?(@acl_default_customized_by_set_default_acl) && @acl_default_customized_by_set_default_acl raise ArgumentError, "#{self}: cannot combine `acl_policy` with `set_default_acl`. " \ "This class already calls `set_default_acl`. Use the declarative " \ "DSL for the entire ACL configuration, or remove `acl_policy` and " \ "use only `set_default_acl`." end # `owner: :self` is a special marker meaning "the record itself is # its own owner" — only meaningful for Parse::User and subclasses, # where the record IS a user. The save-time resolver pre-generates # `@id` via Parse::Core::ParseReference.generate_object_id when # blank so the ACL can grant R/W to the record's own objectId in # a single roundtrip. Non-User classes have no sensible # interpretation (a Post's objectId is not a user id). if owner == :self && !(self <= Parse::User) raise ArgumentError, "#{self}: `owner: :self` is only supported on Parse::User and " \ "its subclasses (the record IS the owner). For other classes, " \ "declare a belongs_to pointer to the owning user." end if owner && !policy.to_s.start_with?("owner_") warn "[#{self}] `owner:` is ignored when acl_policy is #{policy.inspect}; only :owner_else_public, :owner_else_private, and :owner_but_public_read use it." end if owner.nil? && policy.to_s.start_with?("owner_") fallback = case policy when :owner_else_public then "public R/W" when :owner_but_public_read then "public read only" else "master-key-only" end warn "[#{self}] acl_policy #{policy.inspect} declared without `owner:` field; ACL resolution will always use the fallback (#{fallback}). Pass `as:` at construction to override." end @acl_policy_setting = policy @acl_owner_field = owner # Reset materialized default_acls so it picks up the new policy's fallback half. @default_acls = nil # Re-arm the permissive-default warning so a subsequent change is re-evaluated. @_permissive_default_warned = nil policy end |
.acl_policy_setting ⇒ Symbol
The effective ACL policy for this class. Inherits from the superclass
when not explicitly declared. The gem-wide default is
:owner_else_private — records grant read/write to the resolved
owner (from as: or the class's owner: field) when one is
supplied, and fall back to master-key-only when no owner is
resolvable. default_acl_private = true is honored as :private.
Classes that need public access for new records should declare
acl_policy :public or :owner_else_public explicitly, or use
the legacy set_default_acl additive API.
554 555 556 557 558 559 560 561 562 563 564 |
# File 'lib/parse/model/object.rb', line 554 def acl_policy_setting return @acl_policy_setting if defined?(@acl_policy_setting) && @acl_policy_setting return :private if default_acl_private if self == Parse::Object :owner_else_private elsif superclass.respond_to?(:acl_policy_setting) superclass.acl_policy_setting else :owner_else_private end end |
.build(json, table = nil, fetched_keys: nil, nested_fetched_keys: nil) ⇒ Parse::Object
If a Parse class object hash is encoutered for which we don't have a corresponding Parse::Object subclass for, a Parse::Pointer will be returned instead.
Method used for decoding JSON objects into their corresponding Object subclasses. The first parameter is a hash containing the object data and the second parameter is the name of the table / class if it is known. If it is not known, we we try and determine it by checking the "className" or :className entries in the hash.
1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 |
# File 'lib/parse/model/object.rb', line 1730 def self.build(json, table = nil, fetched_keys: nil, nested_fetched_keys: nil) # Precedence (most → least authoritative): # 1. Caller-supplied +table+ — caller knows the expected class # (e.g. webhook payload routed to a typed handler, has_many that # knows its declared target class). # 2. The subclass +parse_class+ when invoked on a Parse::Object # subclass directly (Song.build(json)). # 3. The className inside the JSON — only trusted when neither of # the above is available (e.g. base-class +Parse::Object.build+ # on untyped JSON). # Warn on mismatch between an explicit caller class and the # payload-supplied className so type-confusion attacks surface in # logs. incoming_class = nil if json.is_a?(Hash) incoming_class = json[Parse::Model::KEY_CLASS_NAME] || json[:className] end className = table if className.nil? && parse_class != BASE_OBJECT_CLASS className = parse_class end className ||= incoming_class if className && incoming_class && incoming_class != className warn "[Parse::Object.build] expected className=#{className.inspect}, ignoring incoming className=#{incoming_class.inspect}" end if json.is_a?(Hash) && json["error"].present? && json["code"].present? warn "[Parse::Object] Detected object hash with 'error' and 'code' set. : #{json}" end return if className.nil? # we should do a reverse lookup on who is registered for a different class type # than their name with parse_class klass = Parse::Model.find_class className o = nil if klass.present? # when creating objects from Parse JSON data, don't use dirty tracking since # we are considering these objects as "pristine" o = klass.allocate # Set BOTH nested_fetched_keys AND fetched_keys BEFORE initialize # to ensure partially_fetched? returns correct value during attribute application o.instance_variable_set(:@_nested_fetched_keys, nested_fetched_keys) if nested_fetched_keys.present? if fetched_keys.present? # Process fetched_keys like the setter does - convert to symbols and include :id processed_keys = fetched_keys.map { |k| Parse::Query.format_field(k).to_sym } processed_keys << :id unless processed_keys.include?(:id) processed_keys << :objectId unless processed_keys.include?(:objectId) processed_keys.uniq! o.instance_variable_set(:@_fetched_keys, processed_keys) end # Trusted hydration: this path runs on server-side JSON (response # bodies, webhook payloads that have already been scrubbed, # autofetch results). Server responses legitimately include # protected keys like +sessionToken+, +_rperm+ that must populate # the in-memory object. Untrusted +klass.new(hash)+ callers # default to filter those keys. The +@_trusted_init+ ivar is the # signal — see {#initialize} for why we don't use a kwarg. o.instance_variable_set(:@_trusted_init, true) o.send(:initialize, json) else o = Parse::Pointer.new className, (json[Parse::Model::OBJECT_ID] || json[:objectId]) end return o # rescue NameError => e # puts "Parse::Object.build constant class error: #{e}" # rescue Exception => e # puts "Parse::Object.build error: #{e}" end |
.class_permissions ⇒ Parse::CLP Also known as: clp
The Class-Level Permissions for this model. CLPs control access to the class at the schema level.
644 645 646 |
# File 'lib/parse/model/object.rb', line 644 def @class_permissions ||= Parse::CLP.new end |
.default_acls ⇒ Parse::ACL
The set of default ACLs to be applied on newly created instances of this class. By default, public read and write are enabled unless default_acl_private is true.
390 391 392 393 394 395 396 397 |
# File 'lib/parse/model/object.rb', line 390 def default_acls @default_acls ||= case acl_policy_setting when :public, :owner_else_public then Parse::ACL.everyone when :public_read, :owner_but_public_read then Parse::ACL.everyone(true, false) when :private, :owner_else_private then Parse::ACL.private else Parse::ACL.everyone end end |
.describe_access ⇒ Hash
Introspect the locally-configured access surface for this class. Combines the CLP operations, protectedFields read-side hiding, and the write-side protections installed via the field_guards DSL into a single hash, so it's easy to audit who can do what to which fields without reading three separate parts of the class body.
The hash is built from the Parse-Stack model declarations only. It
does NOT round-trip the Parse Server schema; if you've configured
CLPs on the server side that haven't been mirrored locally, those
won't appear here. Conversely, calling update_clp! pushes what
this method reflects.
1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 |
# File 'lib/parse/model/object.rb', line 1005 def describe_access perms = protected_by_pattern = perms.respond_to?(:protected_fields) ? perms.protected_fields : {} guards_map = respond_to?(:field_guards) && field_guards ? field_guards : {} # Per-field access summary. Iterate `field_map` (local -> remote) # rather than `fields`, because `fields` redundantly stores BOTH # the local key (e.g. :full_name) and the remote key (:fullName) # for every property. That redundancy would cause multi-word # properties to appear twice in the output. per_field = {} field_map.each do |local_sym, remote_sym| local_sym = local_sym.to_sym next if Parse::Properties::CORE_FIELDS.key?(local_sym) data_type = fields[local_sym] remote = remote_sym.to_s # Read protection -- collect every protectedFields pattern that # lists this field (under either its local or remote name). hidden_from = protected_by_pattern.each_with_object([]) do |(pattern, hidden_fields), acc| acc << pattern if hidden_fields.include?(remote) || hidden_fields.include?(local_sym.to_s) end per_field[local_sym] = { write: guards_map[local_sym] || :open, read: hidden_from.empty? ? :open : { hidden_from: hidden_from }, type: data_type, } end # Deep-copy the operations hash so callers mutating the result # don't accidentally mutate the live class_permissions state. operations = if perms.respond_to?(:permissions) perms..transform_values { |v| v.is_a?(Hash) ? v.dup : v } else {} end { operations: operations, read_user_fields: perms.respond_to?(:read_user_fields) ? perms.read_user_fields : [], write_user_fields: perms.respond_to?(:write_user_fields) ? perms.write_user_fields : [], fields: per_field, } end |
.fetch_clp(client: nil) ⇒ Parse::CLP Also known as: fetch_class_permissions
Fetch the current CLP from the Parse Server for this class.
1054 1055 1056 1057 1058 1059 1060 1061 |
# File 'lib/parse/model/object.rb', line 1054 def fetch_clp(client: nil) client ||= self.client response = client.schema(parse_class) return Parse::CLP.new unless response.success? clp_data = response.result["classLevelPermissions"] || {} Parse::CLP.new(clp_data) end |
.filter_results_for_user(objects, user, roles: [], authenticated: nil, clp: nil) ⇒ Array<Hash>
Filter an array of Parse objects or hashes for a user. Class method that applies CLP filtering to multiple results.
1157 1158 1159 1160 1161 1162 1163 1164 1165 |
# File 'lib/parse/model/object.rb', line 1157 def self.filter_results_for_user(objects, user, roles: [], authenticated: nil, clp: nil) clp ||= return objects.map { |o| o.is_a?(Parse::Object) ? o.as_json : o } unless clp.present? objects.map do |obj| data = obj.is_a?(Parse::Object) ? obj.as_json : obj clp.filter_fields(data, user: user, roles: roles, authenticated: authenticated) end end |
.master_only_class! ⇒ void
This method returns an undefined value.
Lock every CLP operation to master-key access only. Use as a starting point when a class should be entirely hidden from clients; you can then selectively open specific operations with set_clp or set_class_access afterward.
800 801 802 803 |
# File 'lib/parse/model/object.rb', line 800 def master_only_class! Parse::CLP::OPERATIONS.each { |op| set_clp(op) } nil end |
.pointer(id) ⇒ Parse::Pointer
Helper method to create a Parse::Pointer object for a given id.
1409 1410 1411 1412 |
# File 'lib/parse/model/object.rb', line 1409 def self.pointer(id) return nil if id.nil? Parse::Pointer.new self.parse_class, id end |
.private_acl! ⇒ Object
Convenience method to set default ACL to private (no public access).
Equivalent to self.default_acl_private = true.
358 359 360 |
# File 'lib/parse/model/object.rb', line 358 def private_acl! self.default_acl_private = true end |
.protect_fields(pattern, fields) ⇒ Object Also known as: set_protected_fields
Define protected fields that should be hidden from certain users/roles. This is used to implement field-level security.
Field names are automatically converted from snake_case (Ruby convention) to camelCase (Parse Server convention). You can use either format.
943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 |
# File 'lib/parse/model/object.rb', line 943 def protect_fields(pattern, fields) pattern = "*" if pattern.to_sym == :public rescue pattern # Convert userField:field_name pattern to use camelCase field name if pattern.to_s.start_with?("userField:") field_name = pattern.to_s.sub("userField:", "") field_sym = field_name.to_sym converted_field = field_map[field_sym] || field_name.camelize(:lower) pattern = "userField:#{converted_field}" end # Convert snake_case Ruby property names to camelCase Parse field names converted_fields = Array(fields).map do |field| field_sym = field.to_sym # Use field_map if available, otherwise convert to camelCase field_map[field_sym] || field.to_s.camelize(:lower) end .set_protected_fields(pattern, converted_fields) end |
.roles_for_user(user) ⇒ Array<String>
Fetch a user's roles for use with field filtering. Convenience method to get role names that can be passed to filter methods.
1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 |
# File 'lib/parse/model/object.rb', line 1176 def self.roles_for_user(user) return [] unless user.is_a?(Parse::User) || user.is_a?(Parse::Pointer) return [] unless defined?(Parse::Role) user_id = user.respond_to?(:id) ? user.id : user.to_s return [] if user_id.blank? Parse::Role.all(users: user).map(&:name) rescue => e warn "[Parse] Error fetching roles for user: #{e.}" [] end |
.set_class_access(**ops_to_access) ⇒ void
This method returns an undefined value.
Set CLP for multiple operations in one call, choosing a coarse access mode per operation. Each value can be:
:master/:master_only/nil/false-- master key only (Parse Server's empty{}permission for that op):public/true-- wildcard*access:authenticated-- requiresAuthentication- a String or Symbol -- a single role name
(the
role:prefix is added automatically) - an Array of Strings/Symbols -- multiple role names
Operations not listed in the hash are left at their current setting. For finer control (mixed roles, users, pointer-fields, requires_authentication) use set_clp directly.
861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 |
# File 'lib/parse/model/object.rb', line 861 def set_class_access(**ops_to_access) ops_to_access.each do |op, access| op = op.to_sym unless Parse::CLP::OPERATIONS.include?(op) raise ArgumentError, "Unknown CLP operation #{op.inspect}. Allowed: #{Parse::CLP::OPERATIONS.inspect}" end case access when :master, :master_only, nil, false set_clp(op) when :public, true set_clp(op, public: true) when :authenticated set_clp(op, requires_authentication: true) when Array set_clp(op, roles: access.map(&:to_s)) when String, Symbol set_clp(op, roles: [access.to_s]) else raise ArgumentError, "Unknown class_access value for :#{op}: #{access.inspect}. " \ "Use :master, :public, :authenticated, a role name, or an array of roles." end end nil end |
.set_clp(operation, public: nil, roles: [], users: [], pointer_fields: [], requires_authentication: false) ⇒ Object Also known as: set_class_permission
Set a class-level permission for a specific operation. This is the main DSL method for configuring CLPs in your model.
763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 |
# File 'lib/parse/model/object.rb', line 763 def set_clp(operation, public: nil, roles: [], users: [], pointer_fields: [], requires_authentication: false) # Convert snake_case pointer field names to camelCase converted_pointer_fields = Array(pointer_fields).map do |field| field_sym = field.to_sym field_map[field_sym] || field.to_s.camelize(:lower) end .( operation, public_access: public, roles: Array(roles), users: Array(users), pointer_fields: converted_pointer_fields, requires_authentication: requires_authentication ) end |
.set_default_acl(id, read: false, write: false, role: false) ⇒ Object
A method to set default ACLs to be applied for newly created instances of this class. All subclasses have public read and write enabled by default.
423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 |
# File 'lib/parse/model/object.rb', line 423 def set_default_acl(id, read: false, write: false, role: false) unless id.present? raise ArgumentError, "Invalid argument applying #{self}.default_acls : must be either objectId, role or :public" end # Mixing the declarative `acl_policy` DSL with the legacy additive # `set_default_acl` API on the same class produces ambiguous behavior # (which one wins at save time? which fields get which permissions?). # Pick one and stick with it. if defined?(@acl_policy_setting) && @acl_policy_setting raise ArgumentError, "#{self}: cannot combine `set_default_acl` with `acl_policy`. " \ "This class already declares `acl_policy #{@acl_policy_setting.inspect}`. " \ "Use the declarative DSL for the entire ACL configuration, or remove " \ "`acl_policy` and use only `set_default_acl` (the legacy additive API)." end # Mark the class as using the legacy additive ACL API. The save-time # policy resolver respects this and leaves the init-stamped default # ACL alone, preserving pre-4.1 behavior for classes that customize # via set_default_acl. @acl_default_customized_by_set_default_acl = true role ? default_acls.apply_role(id, read, write) : default_acls.apply(id, read, write) end |
.set_default_clp(public: nil, roles: [], requires_authentication: false) ⇒ Object
Set default permissions for all CLP operations at once. This is useful for establishing a baseline before customizing specific operations.
679 680 681 682 683 684 685 686 687 688 689 690 691 692 |
# File 'lib/parse/model/object.rb', line 679 def set_default_clp(public: nil, roles: [], requires_authentication: false) # Set the default permission on the CLP instance # This will be used by as_json to fill in missing operations .( public_access: public, roles: Array(roles), requires_authentication: requires_authentication ) # Also explicitly set all operations to ensure they're included Parse::CLP::OPERATIONS.each do |operation| set_clp(operation, public: public, roles: roles, requires_authentication: requires_authentication) end end |
.set_read_user_fields(*fields) ⇒ Object
Set pointer-permission fields for read access. Users pointed to by these fields can read objects of this class. This is an alternative to ACLs for owner-based access control.
707 708 709 710 711 712 713 |
# File 'lib/parse/model/object.rb', line 707 def set_read_user_fields(*fields) converted = fields.flatten.map do |f| field_sym = f.to_sym field_map[field_sym] || f.to_s.camelize(:lower) end .set_read_user_fields(*converted) end |
.set_write_user_fields(*fields) ⇒ Object
Set pointer-permission fields for write access. Users pointed to by these fields can write to objects of this class.
726 727 728 729 730 731 732 |
# File 'lib/parse/model/object.rb', line 726 def set_write_user_fields(*fields) converted = fields.flatten.map do |f| field_sym = f.to_sym field_map[field_sym] || f.to_s.camelize(:lower) end .set_write_user_fields(*converted) end |
.unlistable_class! ⇒ void
This method returns an undefined value.
Restrict find and count to master-key only, leaving the other
operations (get, create, update, delete, addField) at their
current settings. This is the canonical "Installation-style" pattern:
clients can interact with individual records but cannot enumerate or
count them.
818 819 820 821 822 |
# File 'lib/parse/model/object.rb', line 818 def unlistable_class! set_clp(:find) set_clp(:count) nil end |
.update_clp!(client: nil, replace: false) ⇒ Parse::Response Also known as: update_class_permissions!
Update the CLP on the Parse Server for this class. Merges local CLP with any existing server CLP.
1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 |
# File 'lib/parse/model/object.rb', line 1077 def update_clp!(client: nil, replace: false) client ||= self.client unless client.master_key.present? warn "[Parse] CLP changes for #{parse_class} require the master key!" return nil end clp_data = .as_json return nil if clp_data.empty? schema_update = { "classLevelPermissions" => clp_data } client.update_schema(parse_class, schema_update) end |
.wait_for(**kwargs, &block) ⇒ Object
Block until the first row matching Core::Querying#where (and an optional predicate block) arrives via LiveQuery. See Console.wait_for.
198 199 200 |
# File 'lib/parse/console.rb', line 198 def wait_for(**kwargs, &block) Parse::Console.wait_for(self, **kwargs, &block) end |
.watch(**kwargs, &block) ⇒ Object
Tail this class as LiveQuery events arrive — blocking, Ctrl-C to stop. See Console.watch.
191 192 193 |
# File 'lib/parse/console.rb', line 191 def watch(**kwargs, &block) Parse::Console.watch(self, **kwargs, &block) end |
.webhook(type, &block) { ... } ⇒ OpenStruct
Register a webhook trigger or function for this subclass.
60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 |
# File 'lib/parse/webhooks.rb', line 60 def self.webhook(type, &block) if type == :function unless block.is_a?(String) || block.is_a?(Symbol) raise ArgumentError, "Invalid Cloud Code function name: #{block}" end Parse::Webhooks.route(:function, block, &block) # then block must be a symbol or a string else if block_given? Parse::Webhooks.route(type, self, &block) else Parse::Webhooks.route(type, self, block) end end #if block end |
.webhook_function(functionName, &block) { ... } ⇒ OpenStruct
Register a webhook function for this subclass.
36 37 38 39 40 41 42 43 44 |
# File 'lib/parse/webhooks.rb', line 36 def self.webhook_function(functionName, &block) if block_given? Parse::Webhooks.route(:function, functionName, &block) else block = functionName.to_s.underscore.to_sym if block.blank? block = method(block.to_sym) if block.is_a?(Symbol) Parse::Webhooks.route(:function, functionName, block) end end |
Instance Method Details
#[](key) ⇒ Object
Access the value for a defined property through hash accessor. This method returns nil if the key is not one of the defined properties for this Parse::Object subclass.
2006 2007 2008 2009 |
# File 'lib/parse/model/object.rb', line 2006 def [](key) return nil unless self.class.fields[key.to_sym].present? send(key) end |
#[]=(key, value) ⇒ Object
Set the value for a specific property through a hash accessor. This method does nothing if key is not one of the defined properties for this Parse::Object subclass.
2017 2018 2019 2020 |
# File 'lib/parse/model/object.rb', line 2017 def []=(key, value) return unless self.class.fields[key.to_sym].present? send("#{key}=", value) end |
#__type ⇒ Model::TYPE_OBJECT
185 |
# File 'lib/parse/model/object.rb', line 185 def __type; Parse::Model::TYPE_OBJECT; end |
#_resolve_acl_owner_id(owner) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Resolves an as: value or owner-field pointer to an objectId string.
Strictly type-gated to Parse::User-shaped inputs to prevent accidental
ACL grants to non-user records (Roles use role: ACL keys, not raw
objectIds; pointers to non-User classes would silently grant access to
whatever record happens to share that objectId in the User collection).
Accepted forms:
- Parse::User instance
- Parse::Pointer with parse_class == "_User"
- Raw objectId String (caller's responsibility to ensure it is a user id)
Anything else returns nil and the policy falls through to its else-half.
1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 |
# File 'lib/parse/model/object.rb', line 1913 def _resolve_acl_owner_id(owner) return nil if owner.nil? return nil if owner.respond_to?(:empty?) && owner.empty? if owner.is_a?(Parse::Pointer) return nil unless owner.parse_class == Parse::Model::CLASS_USER return owner.id if owner.id.present? return nil end return owner if owner.is_a?(String) && owner.present? nil end |
#_resolve_default_acl ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Save-time resolver for the declarative acl_policy default ACL.
Runs as a before_save callback. If the caller has not overridden the
ACL (no acl= since the init-time default stamp), resolves an owner
from @_acl_owner_override (the as: kwarg) or from the class's
declared owner field, and applies an owner-only ACL. Falls back to
the policy's else-half (:public or :private) when no owner is
resolvable.
1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 |
# File 'lib/parse/model/object.rb', line 1823 def _resolve_default_acl return true unless defined?(@_acl_pristine) && @_acl_pristine # Legacy classes that customize defaults via set_default_acl opt out # of the policy resolver: the init-time stamp already reflects the # caller's intent and we must not overwrite it. return true if self.class.acl_default_customized_by_set_default_acl? # Built-in Parse classes (User, Installation, Session, …) are exempt # by default; see the matching guard in #initialize. Parse Server # applies its own ACL defaults when the save body omits the `ACL` # field, and those defaults (e.g. `_User` → self-write + public read) # are the right answer in nearly every case. Applications that need # to customize a built-in's ACL policy do so by calling `acl_policy` # or `set_default_acl` on the class — that flips # `builtin_acl_default_active?` to false and re-enables both the # init-time stamp and this resolver for that class. return true if self.class.builtin_acl_default_active? policy = self.class.acl_policy_setting owner = @_acl_owner_override if defined?(@_acl_owner_override) if owner.nil? && (field = self.class.acl_owner_field) owner = if field == :self # Self-referential ownership (Parse::User only — enforced at # declaration time). Pre-generate a Parse-compatible objectId # client-side so the ACL grant can reference the record's own # id in the same POST body that creates it. Skipped when the id # is already set (e.g. when re-saving an existing user, or when # parse_reference precompute already ran). @id = Parse::Core::ParseReference.generate_object_id if @id.blank? @id elsif respond_to?(field) send(field) end end owner_id = _resolve_acl_owner_id(owner) target_acl = case policy when :public Parse::ACL.everyone(true, true) when :public_read Parse::ACL.everyone(true, false) when :private Parse::ACL.private when :owner_else_public if owner_id acl = Parse::ACL.new acl.apply(owner_id, true, true) acl else Parse::ACL.everyone(true, true) end when :owner_else_private if owner_id acl = Parse::ACL.new acl.apply(owner_id, true, true) acl else Parse::ACL.private end when :owner_but_public_read acl = Parse::ACL.everyone(true, false) acl.apply(owner_id, true, true) if owner_id acl end # Only re-stamp if the resolved ACL differs from the init-time stamp; # this avoids an unnecessary dirty mark on the acl field for `:public` # / `:private` policies where the init stamp already matches. if @acl.nil? || @acl.as_json != target_acl.as_json self.acl = target_acl.as_json end # @_acl_pristine is now false via #acl_will_change! (when re-stamped) # or it remains true (when nothing needed to change); either way the # resolver has done its job and need not run again. Return a non-false # value so the save callback chain is not halted by the model's # terminator (`result_lambda.call == false`). @_acl_pristine = false true end |
#acl_changed? ⇒ Boolean
Override acl_changed? to compare actual ACL content, not just object references. This ensures that setting an ACL to identical values doesn't mark it as changed.
1970 1971 1972 1973 1974 1975 1976 1977 |
# File 'lib/parse/model/object.rb', line 1970 def acl_changed? # First check if ActiveModel thinks it changed return false unless super # Then verify the content actually changed by comparing JSON representations acl_was_json = acl_was.respond_to?(:as_json) ? acl_was.as_json : acl_was acl_current_json = @acl&.respond_to?(:as_json) ? @acl.as_json : @acl acl_was_json != acl_current_json end |
#acl_was ⇒ Parse::ACL
Override acl_was to return the captured snapshot instead of the reference stored by ActiveModel's dirty tracking.
1958 1959 1960 1961 1962 1963 1964 1965 |
# File 'lib/parse/model/object.rb', line 1958 def acl_was # If we have a snapshot, return it; otherwise fall back to ActiveModel's behavior if defined?(@_acl_snapshot_before_change) && @_acl_snapshot_before_change @_acl_snapshot_before_change else super end end |
#acl_will_change! ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Override acl_will_change! to capture a snapshot of the ACL before modification. This is necessary because ACL is a mutable object that can be modified in place (via apply, apply_role, etc.). Without this, acl_was would return a reference to the same object as acl, making them appear identical after in-place changes.
Also clears the ACL-pristine flag so the save-time default-ACL resolver
leaves caller-set ACLs alone. The initial default stamp performed in
#initialize is excluded by re-asserting @_acl_pristine = true after
the stamp, so this hook can safely treat any subsequent change as a
caller intent to override.
1938 1939 1940 1941 1942 1943 1944 1945 1946 |
# File 'lib/parse/model/object.rb', line 1938 def acl_will_change! # Only capture snapshot on the first change (before any modifications) unless defined?(@_acl_snapshot_before_change) && @_acl_snapshot_before_change # Deep copy the ACL by creating a new one from its JSON representation @_acl_snapshot_before_change = @acl ? Parse::ACL.new(@acl.as_json) : Parse::ACL.new end @_acl_pristine = false if defined?(@_acl_pristine) super end |
#after_create { ... } ⇒ Object
A callback called after the object has been created.
|
|
# File 'lib/parse/model/object.rb', line 187
|
#after_destroy { ... } ⇒ Object
This is not related to a Parse afterDelete webhook trigger.
A callback called after the object has been successfully deleted.
|
|
# File 'lib/parse/model/object.rb', line 187
|
#after_save { ... } ⇒ Object
This is not related to a Parse afterSave webhook trigger.
A callback called after the object has been successfully saved.
|
|
# File 'lib/parse/model/object.rb', line 187
|
#after_update { ... } ⇒ Object
A callback called after the object has been updated.
|
|
# File 'lib/parse/model/object.rb', line 187
|
#after_validation { ... } ⇒ Object
A callback called after validations are run.
|
|
# File 'lib/parse/model/object.rb', line 187
|
#apply_defaults! ⇒ Array
force apply default values for any properties defined with default values.
1396 1397 1398 1399 1400 1401 1402 1403 1404 |
# File 'lib/parse/model/object.rb', line 1396 def apply_defaults! self.class.defaults_list.each do |key| # Skip applying defaults to unfetched fields on selectively fetched objects. # This preserves the ability to autofetch when the field is accessed. next if has_selective_keys? && !field_was_fetched?(key) send(key) # should call set default proc/values if nil end end |
#around_create { ... } ⇒ Object
A callback called around object creation.
|
|
# File 'lib/parse/model/object.rb', line 187
|
#around_destroy { ... } ⇒ Object
A callback called around object destruction.
|
|
# File 'lib/parse/model/object.rb', line 187
|
#around_save { ... } ⇒ Object
A callback called around object save.
|
|
# File 'lib/parse/model/object.rb', line 187
|
#around_update { ... } ⇒ Object
A callback called around object update.
|
|
# File 'lib/parse/model/object.rb', line 187
|
#around_validation { ... } ⇒ Object
A callback called around validations.
|
|
# File 'lib/parse/model/object.rb', line 187
|
#as_json(opts = nil) ⇒ Hash
Returns a json-hash representing this object.
1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 |
# File 'lib/parse/model/object.rb', line 1208 def as_json(opts = nil) opts ||= {} # Normalize :exclude_keys and :exclude to :except (alias support) if !opts[:except] if opts[:exclude_keys] opts = opts.merge(except: opts[:exclude_keys]) elsif opts[:exclude] opts = opts.merge(except: opts[:exclude]) end end # `:vector` fields are excluded from serialization by default — # embeddings are large (often 1024–4096 floats), they leak ML # signal to clients, and they round-trip through the dedicated # embed/find_similar pipelines rather than the standard REST # save/find. Pass `include_vectors: true` to opt back in (e.g., # for tests or internal mongo-direct bulk writes). unless opts[:include_vectors] == true vector_fields = self.class.respond_to?(:fields) ? self.class.fields(:vector).keys.map(&:to_s) : [] if vector_fields.any? except = Array(opts[:except]).map(&:to_s) | vector_fields opts = opts.merge(except: except) end end # When :only is specified without :strict, automatically include identification fields # so the serialized object can be properly identified if opts[:only] && !opts[:strict] only_keys = Array(opts[:only]).map(&:to_s) only_keys |= IDENTIFICATION_FIELDS opts = opts.merge(only: only_keys) end # For selectively fetched objects (partial fetch), serialize only the fetched fields. # This takes priority over pointer detection because a partial fetch has actual data # even if it lacks timestamps (which would otherwise make it look like a pointer). # This behavior is controlled by: # 1. Per-call: opts[:only_fetched] (explicit true/false) # 2. Global: Parse.serialize_only_fetched_fields (default true) if has_selective_keys? # Determine if we should serialize only fetched fields only_fetched = opts.fetch(:only_fetched) { Parse.serialize_only_fetched_fields } if only_fetched && !opts.key?(:only) # Build the :only list from fetched keys # Use the local field names which match the attribute methods only_keys = fetched_keys.map(&:to_s) # Always include Parse metadata fields for proper object identification only_keys |= IDENTIFICATION_FIELDS only_keys |= %w[created_at updated_at] opts = opts.merge(only: only_keys) end changed_fields = changed_attributes return super(opts).delete_if { |k, v| v.nil? && !changed_fields.has_key?(k) } end # When in pointer state (no data fetched, just an objectId), return the serialized # pointer hash (with __type, className, objectId) for proper JSON serialization return pointer.as_json(opts) if pointer? changed_fields = changed_attributes super(opts).delete_if { |k, v| v.nil? && !changed_fields.has_key?(k) } end |
#autofetch_disabled? ⇒ Boolean
Returns whether autofetch is disabled for this instance.
1552 1553 1554 |
# File 'lib/parse/model/object.rb', line 1552 def autofetch_disabled? @_autofetch_disabled == true end |
#before_create { ... } ⇒ Object
A callback called before the object has been created.
|
|
# File 'lib/parse/model/object.rb', line 187
|
#before_destroy { ... } ⇒ Object
This is not related to a Parse beforeDelete webhook trigger.
A callback called before the object is about to be deleted.
|
|
# File 'lib/parse/model/object.rb', line 187
|
#before_save { ... } ⇒ Object
This is not related to a Parse beforeSave webhook trigger.
A callback called before the object is saved.
|
|
# File 'lib/parse/model/object.rb', line 187
|
#before_update { ... } ⇒ Object
A callback called before the object is updated (not on create).
|
|
# File 'lib/parse/model/object.rb', line 187
|
#before_validation { ... } ⇒ Object
A callback called before validations are run.
|
|
# File 'lib/parse/model/object.rb', line 187
|
#changed ⇒ Array<String>
Override changed to filter out ACL when its content hasn't actually changed. This ensures dirty? returns false when ACL is rebuilt to identical values. For new objects, ACL is always included since it needs to be sent to the server.
1983 1984 1985 1986 1987 1988 1989 1990 1991 |
# File 'lib/parse/model/object.rb', line 1983 def changed result = super.dup # If ACL is in the changed list but content is identical, remove it # BUT keep it if the object is new (needs to be sent to server) if result.include?("acl") && !new? && !acl_changed? result.delete("acl") end result end |
#changed? ⇒ Boolean
Override changed? to use our filtered changed list. ActiveModel's changed? uses internal tracking that doesn't account for ACL content comparison.
1997 1998 1999 |
# File 'lib/parse/model/object.rb', line 1997 def changed? changed.any? end |
#clear_attribute_change!(atts) ⇒ Object
clear all change and dirty tracking information.
1705 1706 1707 |
# File 'lib/parse/model/object.rb', line 1705 def clear_attribute_change!(atts) clear_attribute_changes(atts) end |
#clear_changes! ⇒ Object
clears all dirty tracking information
1448 1449 1450 1451 1452 |
# File 'lib/parse/model/object.rb', line 1448 def clear_changes! clear_changes_information # Clear the ACL snapshot used for proper acl_was tracking @_acl_snapshot_before_change = nil end |
#clear_partial_fetch_state! ⇒ void
This method returns an undefined value.
Clears all partial fetch tracking state. Called after successful save since server returns updated object.
1621 1622 1623 1624 |
# File 'lib/parse/model/object.rb', line 1621 def clear_partial_fetch_state! @_fetched_keys = nil @_nested_fetched_keys = nil end |
#disable_autofetch! ⇒ void
This method returns an undefined value.
Disables autofetch for this object instance. Useful for preventing automatic network requests.
1540 1541 1542 |
# File 'lib/parse/model/object.rb', line 1540 def disable_autofetch! @_autofetch_disabled = true end |
#enable_autofetch! ⇒ void
This method returns an undefined value.
Enables autofetch for this object instance (default behavior).
1546 1547 1548 |
# File 'lib/parse/model/object.rb', line 1546 def enable_autofetch! @_autofetch_disabled = false end |
#existed? ⇒ Boolean
You should not use this method inside a beforeSave webhook.
Existed returns true if the object had existed before its last save operation. This method returns false if the #created_at and #updated_at dates of an object are equal, implyiny this object has been newly created and saved (especially in an afterSave hook).
This is a helper method in a webhook afterSave to know if this object was recently saved in the beforeSave webhook. Checking for #existed? == false in an afterSave hook, is equivalent to using #new? in a beforeSave hook.
1491 1492 1493 1494 1495 1496 |
# File 'lib/parse/model/object.rb', line 1491 def existed? if @id.blank? || @created_at.blank? || @updated_at.blank? return false end created_at != updated_at end |
#fetched? ⇒ Boolean
Returns whether this object has been fetched from the server (fully or partially). Overrides Pointer#fetched? to return true for any object with data.
1525 1526 1527 |
# File 'lib/parse/model/object.rb', line 1525 def fetched? !pointer? end |
#fetched_keys ⇒ Array<Symbol>
Returns the array of keys that were fetched for this object. Empty array means the object was fully fetched. Returns a frozen duplicate to prevent external mutation.
1533 1534 1535 |
# File 'lib/parse/model/object.rb', line 1533 def fetched_keys (@_fetched_keys || []).dup.freeze end |
#fetched_keys=(keys) ⇒ Array
Sets the fetched keys for this object. Used internally when building objects from partial fetch queries.
1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 |
# File 'lib/parse/model/object.rb', line 1560 def fetched_keys=(keys) if keys.nil? || keys.empty? @_fetched_keys = nil else # Always include :id and convert to symbols @_fetched_keys = keys.map { |k| Parse::Query.format_field(k).to_sym } @_fetched_keys << :id unless @_fetched_keys.include?(:id) @_fetched_keys << :objectId unless @_fetched_keys.include?(:objectId) @_fetched_keys.uniq! end @_fetched_keys end |
#field_was_fetched?(key) ⇒ Boolean
Returns whether a specific field was fetched for this object. Base keys (id, created_at, updated_at) are always considered fetched.
1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 |
# File 'lib/parse/model/object.rb', line 1577 def field_was_fetched?(key) # If not partially fetched (i.e., still a pointer), all fields are NOT fetched return false if pointer? # If no selective keys were specified, this is a fully fetched object # All fields are considered fetched return true unless has_selective_keys? key = key.to_sym # Base keys are always considered fetched return true if Parse::Properties::BASE_KEYS.include?(key) return true if key == :acl || key == :ACL # Check both local key and remote field name # Convert remote_key to symbol for consistent comparison remote_key = self.field_map[key]&.to_sym @_fetched_keys.include?(key) || (remote_key && @_fetched_keys.include?(remote_key)) end |
#filter_for_user(user, roles: [], authenticated: nil, clp: nil) ⇒ Hash
Filter this object's fields based on Class-Level Permissions for a user. Uses the CLP configured on the model class to determine which fields should be visible to the given user/roles context.
This is useful for filtering webhook responses or API data before sending to clients.
1135 1136 1137 1138 1139 1140 |
# File 'lib/parse/model/object.rb', line 1135 def filter_for_user(user, roles: [], authenticated: nil, clp: nil) clp ||= self.class. return as_json unless clp.present? clp.filter_fields(as_json, user: user, roles: roles, authenticated: authenticated) end |
#fully_fetched? ⇒ Boolean
Returns whether this object is fully fetched with all fields available. Returns false if the object is a pointer or was fetched with specific keys.
1518 1519 1520 |
# File 'lib/parse/model/object.rb', line 1518 def fully_fetched? !pointer? && !has_selective_keys? end |
#has?(key) ⇒ Boolean
Check if a field has a value (is present and not nil).
2033 2034 2035 2036 2037 |
# File 'lib/parse/model/object.rb', line 2033 def has?(key) return false unless self.class.fields[key.to_sym].present? value = send(key) !value.nil? end |
#has_selective_keys? ⇒ Boolean
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Returns whether this object was fetched with specific keys (selective fetch). When selectively fetched, accessing unfetched fields will trigger an autofetch. This is an internal method used for autofetch logic.
1503 1504 1505 |
# File 'lib/parse/model/object.rb', line 1503 def has_selective_keys? @_fetched_keys&.any? || false end |
#keys ⇒ Array<String>
Returns an array of property names (keys) for this Parse::Object. Similar to Hash#keys, this method returns all the defined field names for this object's class.
2026 2027 2028 |
# File 'lib/parse/model/object.rb', line 2026 def keys self.class.fields.keys.map(&:to_s) end |
#nested_fetched_keys ⇒ Hash
Returns the nested fetched keys map for building nested objects.
1598 1599 1600 |
# File 'lib/parse/model/object.rb', line 1598 def nested_fetched_keys @_nested_fetched_keys || {} end |
#nested_fetched_keys=(keys_map) ⇒ Hash
Sets the nested fetched keys map for building nested objects.
1605 1606 1607 |
# File 'lib/parse/model/object.rb', line 1605 def nested_fetched_keys=(keys_map) @_nested_fetched_keys = keys_map.is_a?(Hash) ? keys_map : nil end |
#nested_keys_for(field_name) ⇒ Array?
Gets the fetched keys for a specific nested field.
1612 1613 1614 1615 1616 |
# File 'lib/parse/model/object.rb', line 1612 def nested_keys_for(field_name) return nil unless @_nested_fetched_keys.present? field_name = field_name.to_sym @_nested_fetched_keys[field_name] end |
#new? ⇒ Boolean
An object is considered new until it has been successfully persisted to
the server. "Persisted" means the server has returned a createdAt
timestamp, which only happens after a successful create. Checking
path assigns @id client-side in a before_create callback, so an
@id-only check would flip mid-callback-chain and confuse user code
(validation on: :create / :update, beforeSave handlers, etc.).
Treating an object as "new" until createdAt arrives keeps semantics
stable from the first before_save through the end of after_create.
1464 1465 1466 |
# File 'lib/parse/model/object.rb', line 1464 def new? @id.blank? || @created_at.nil? end |
#parse_class ⇒ String Also known as: className
Returns the Parse class for this object.
1100 1101 1102 |
# File 'lib/parse/model/object.rb', line 1100 def parse_class self.class.parse_class end |
#partially_fetched? ⇒ Boolean
Returns whether this object was fetched with specific keys (partial/selective fetch). When partially fetched, only the specified keys are available and accessing other fields will trigger an autofetch. Returns false for pointers and fully fetched objects.
1511 1512 1513 |
# File 'lib/parse/model/object.rb', line 1511 def partially_fetched? !pointer? && has_selective_keys? end |
#persisted? ⇒ Boolean
Determines if this object has been saved to the Parse database. If an object has pending changes, then it is considered to not yet be persisted.
1417 1418 1419 |
# File 'lib/parse/model/object.rb', line 1417 def persisted? changed? == false && !(@id.nil? || @created_at.nil? || @updated_at.nil? || @acl.nil?) end |
#pretty ⇒ String
Returns a pretty-formatted JSON string.
1700 1701 1702 |
# File 'lib/parse/model/object.rb', line 1700 def pretty JSON.pretty_generate(as_json) end |
#reload!(**opts) ⇒ Object
Force reload from the database and replace any local fields with data from the persistent store. By default, bypasses cache reads but updates the cache with fresh data (write-only mode) so future cached reads get the latest data.
1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 |
# File 'lib/parse/model/object.rb', line 1436 def reload!(**opts) # Default to write-only cache mode - reload always gets fresh data # but updates cache for future cached reads. Controlled by feature flag. unless opts.key?(:cache) opts[:cache] = Parse.cache_write_on_fetch ? :write_only : false end # get the values from the persistence layer fetch!(**opts) clear_changes! end |
#rollback! ⇒ Object
This does not reload the object from the persistent store, for this use "reload!" instead.
Locally restores the previous state of the object and clears all dirty tracking information.
1671 1672 1673 |
# File 'lib/parse/model/object.rb', line 1671 def rollback! restore_attributes end |
#run_after_create_callbacks ⇒ Boolean
Run after_create callbacks for this object. This method is called by webhook handlers when an object is created.
1629 1630 1631 |
# File 'lib/parse/model/object.rb', line 1629 def run_after_create_callbacks run_callbacks_from_list(self.class._create_callbacks, :after) end |
#run_after_delete_callbacks ⇒ Boolean
Run after_destroy callbacks for this object. This method is called by webhook handlers when an object is deleted.
1643 1644 1645 |
# File 'lib/parse/model/object.rb', line 1643 def run_after_delete_callbacks run_callbacks_from_list(self.class._destroy_callbacks, :after) end |
#run_after_save_callbacks ⇒ Boolean
Run after_save callbacks for this object. This method is called by webhook handlers when an object is saved.
1636 1637 1638 |
# File 'lib/parse/model/object.rb', line 1636 def run_after_save_callbacks run_callbacks_from_list(self.class._save_callbacks, :after) end |
#schema ⇒ Hash
Returns the schema structure for this Parse collection from the server.
1108 1109 1110 |
# File 'lib/parse/model/object.rb', line 1108 def schema self.class.schema end |
#search_highlights ⇒ Hash?
Returns Atlas Search highlights blob.
182 |
# File 'lib/parse/model/object.rb', line 182 def search_highlights; @_search_highlights; end |
#search_score ⇒ Float?
Returns Atlas Search relevance score.
179 |
# File 'lib/parse/model/object.rb', line 179 def search_score; @_search_score; end |
#twin ⇒ Parse::Object
This method creates a new object of the same instance type with a copy of all the properties of the current instance. This is useful when you want to create a duplicate record.
1690 1691 1692 1693 1694 1695 1696 |
# File 'lib/parse/model/object.rb', line 1690 def twin h = self.as_json h.delete(Parse::Model::OBJECT_ID) h.delete(:objectId) h.delete(:id) self.class.new h end |
#updates(include_all = false) ⇒ Hash
Returns a hash of all the changes that have been made to the object. By default changes to the Parse::Properties::BASE_KEYS are ignored unless you pass true as an argument.
1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 |
# File 'lib/parse/model/object.rb', line 1653 def updates(include_all = false) h = {} changed.each do |key| next if include_all == false && Parse::Properties::BASE_KEYS.include?(key.to_sym) # lookup the remote Parse field name incase it is different from the local attribute name remote_field = self.field_map[key.to_sym] || key h[remote_field] = send key # make an exception to Parse::Objects, we should return a pointer to them instead h[remote_field] = h[remote_field].parse_pointers if h[remote_field].is_a?(Parse::PointerCollectionProxy) h[remote_field] = h[remote_field].pointer if h[remote_field].respond_to?(:pointer) end h end |
#valid?(context = nil) ⇒ Boolean
Override valid? to run validation callbacks. This wraps the standard ActiveModel validation with our custom :validation callbacks.
1472 1473 1474 1475 1476 1477 1478 |
# File 'lib/parse/model/object.rb', line 1472 def valid?(context = nil) result = true run_callbacks :validation do result = super(context) end result end |
#validate! ⇒ self
Overrides ActiveModel::Validations#validate! instance method. It runs all validations for this object. If validation fails, it raises ActiveModel::ValidationError otherwise it returns the object.
1681 1682 1683 1684 |
# File 'lib/parse/model/object.rb', line 1681 def validate! super self end |
#vector_score ⇒ Float?
Search/vector-search result accessors. Populated by
Parse::AtlasSearch.process_search_results and
Parse::Core::VectorSearchable.build_vector_hits via
instance_variable_set. Defined here once instead of per-result
via define_singleton_method so high-k result sets don't inflate
a singleton class per row, and so a user-defined override on a
subclass can't silently desync from the ivar.
Each returns nil unless the object was returned from the corresponding search path.
176 |
# File 'lib/parse/model/object.rb', line 176 def vector_score; @_vector_score; end |