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

# or per-instance raise on failure

song.save!

Returns:

  • (Boolean)

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

# File 'lib/parse/model/core/actions.rb', line 121

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.


158
159
160
161
162
163
164
165
166
167
168
169
# File 'lib/parse/model/core/actions.rb', line 158

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:


182
183
184
185
186
# File 'lib/parse/model/core/actions.rb', line 182

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.


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
267
268
269
270
271
272
273
274
275
276
# File 'lib/parse/model/core/actions.rb', line 205

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