Module: Parse::Core::Actions::ClassMethods

Defined in:
lib/parse/model/core/actions.rb

Overview

Class methods applied to Parse::Object subclasses.

Instance Attribute Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#raise_on_save_failureBoolean

By 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 RecordNotSaved.

When 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 RecordNotSaved exception type. This exception has an instance method of `#object` which contains the object that failed to save.

Examples:

# globally across all models
Parse::Model.raise_on_save_failure = true
Song.raise_on_save_failure = true # per-model

# or per-instance raise on failure
song.save!

Returns:

  • (Boolean)

    whether to raise a RecordNotSaved when an object fails to save.



134
135
136
# File 'lib/parse/model/core/actions.rb', line 134

def raise_on_save_failure
  @raise_on_save_failure
end

Instance Method Details

#first_or_create(query_attrs = {}, resource_attrs = {}) ⇒ Parse::Object

Finds the first object matching the query conditions, or creates a new unsaved object with the attributes. This method takes the possibility of two hashes, therefore make sure you properly wrap the contents of the input with `{}`.

Examples:

Parse::User.first_or_create({ ..query conditions..})
Parse::User.first_or_create({ ..query conditions..}, {.. resource_attrs ..})

Parameters:

  • query_attrs (Hash) (defaults to: {})

    a set of query constraints that also are applied.

  • resource_attrs (Hash) (defaults to: {})

    a set of attribute values to be applied if an object was not found.

Returns:

  • (Parse::Object)

    a Parse::Object, whether found by the query or newly created.



150
151
152
153
154
155
156
157
158
159
160
# File 'lib/parse/model/core/actions.rb', line 150

def first_or_create(query_attrs = {}, resource_attrs = {})
  query_attrs = query_attrs.symbolize_keys
  resource_attrs = resource_attrs.symbolize_keys
  obj = query(query_attrs).first

  if obj.blank?
    obj = self.new query_attrs
    obj.apply_attributes!(resource_attrs, dirty_track: true)
  end
  obj
end

#first_or_create!(query_attrs = {}, resource_attrs = {}) ⇒ Parse::Object

Finds the first object matching the query conditions, or creates a new saved object with the attributes. This method is similar to #first_or_create but will also Parse::Core::Actions#save! the object if it was newly created.

Examples:

obj = Parse::User.first_or_create!({ ..query conditions..})
obj = Parse::User.first_or_create!({ ..query conditions..}, {.. resource_attrs ..})

Parameters:

  • query_attrs (Hash) (defaults to: {})

    a set of query constraints that also are applied.

  • resource_attrs (Hash) (defaults to: {})

    a set of attribute values to be applied if an object was not found.

Returns:

  • (Parse::Object)

    a Parse::Object, whether found by the query or newly created.

Raises:

See Also:



173
174
175
176
177
# File 'lib/parse/model/core/actions.rb', line 173

def first_or_create!(query_attrs = {}, resource_attrs = {})
  obj = first_or_create(query_attrs, resource_attrs)
  obj.save! if obj.new?
  obj
end

#save_all(constraints = {}) { ... } ⇒ Boolean

Note:

You cannot use :updated_at as a constraint.

Auto save all objects matching the query constraints. This method is meant to be used with a block. Any objects that are modified in the block will be batched for a save operation. This uses the `updated_at` field to continue to query for all matching objects that have not been updated. If you need to use `:updated_at` in your constraints, consider using Querying#all or Querying#each

Examples:


post = Post.first
Comments.save_all( post: post) do |comment|
  # .. modify comment ...
  # it will automatically be saved
end

Parameters:

  • constraints (Hash) (defaults to: {})

    a set of query constraints.

Yields:

  • a block which will iterate through each matching object.

Returns:

  • (Boolean)

    true if all saves succeeded and there were no errors.



196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
# File 'lib/parse/model/core/actions.rb', line 196

def save_all(constraints = {})
  invalid_constraints = constraints.keys.any? do |k|
    (k == :updated_at || k == :updatedAt) ||
    (k.is_a?(Parse::Operation) && (k.operand == :updated_at || k.operand == :updatedAt))
  end
  if invalid_constraints
    raise ArgumentError,
      "[#{self}] Special method save_all() cannot be used with an :updated_at constraint."
  end

  force = false
  batch_size = 250
  iterator_block = nil
  if block_given?
    iterator_block = Proc.new
    force ||= false
  else
    # if no block given, assume you want to just save all objects
    # regardless of modification.
    force = true
  end
  # Only generate the comparison block once.
  # updated_comparison_block = Proc.new { |x| x.updated_at }

  anchor_date = Parse::Date.now
  constraints.merge! :updated_at.on_or_before => anchor_date
  constraints.merge! cache: false
  # oldest first, so we create a reduction-cycle
  constraints.merge! order: :updated_at.asc, limit: batch_size
  update_query = query(constraints)
  #puts "Setting Anchor Date: #{anchor_date}"
  cursor = nil
  has_errors = false
  loop do
    results = update_query.results

    break if results.empty?

    # verify we didn't get duplicates fetches
    if cursor.is_a?(Parse::Object) && results.any? { |x| x.id == cursor.id }
      warn "[#{self}.save_all] Unbounded update detected with id #{cursor.id}."
      has_errors = true
      break cursor
    end

    results.each(&iterator_block) if iterator_block.present?
    # we don't need to refresh the objects in the array with the results
    # since we will be throwing them away. Force determines whether
    # to save these objects regardless of whether they are dirty.
    batch = results.save(merge: false, force: force)

    # faster version assuming sorting order wasn't messed up
    cursor = results.last
    # slower version, but more accurate
    # cursor_item = results.max_by(&updated_comparison_block).updated_at
    # puts "[Parse::SaveAll] Updated #{results.count} records updated <= #{cursor.updated_at}"

    break if results.count < batch_size # we didn't hit a cap on results.
    if cursor.is_a?(Parse::Object)
      update_query.where :updated_at.gte => cursor.updated_at

      if cursor.updated_at.present? && cursor.updated_at > anchor_date
        warn "[#{self}.save_all] Reached anchor date  #{anchor_date} < #{cursor.updated_at}"
        break cursor
      end
    end

    has_errors ||= batch.error?
  end
  not has_errors
end