Module: Mongoid::Persistable::Settable

Extended by:
ActiveSupport::Concern
Included in:
Mongoid::Persistable
Defined in:
lib/mongoid/persistable/settable.rb

Overview

Defines behaviour for $set operations.

Since:

  • 4.0.0

Instance Method Summary collapse

Instance Method Details

#set(setters) ⇒ Document

Perform a $set operation on the provided field/value pairs and set the values in the document in memory.

The key can be a dotted sequence of keys, in which case the top level field is treated as a nested hash and any missing keys are created automatically:

Performing a nested set like this merges values of intermediate keys:

If the top level field was not a hash, its original value is discarded and the field is replaced with a hash.

Note that unlike MongoDB's $set, Mongoid's set writes out the entire field even when setting a subset of the field via the nested hash semantics. This means performing a $set with nested hash semantics can overwrite other hash keys within the top level field in the database.

Examples:

Set the values.

document.set(title: "sir", dob: Date.new(1970, 1, 1))

Set the values using nested hash semantics.

document.set('author.title' => 'Sir')
# => document.author == {'title' => 'Sir'}

Nested hash value merging.

document.set('author.title' => 'Sir')
document.set('author.name' => 'Linus Torvalds')
# => document.author == {'title' => 'Sir', 'name' => 'Linus Torvalds'}

Nested hash overwriting a non-hash value.

document.set('author' => 'John Doe')
document.set('author.title' => 'Sir')
# => document.author == {'title' => 'Sir'}

Parameters:

  • setters (Hash)

    The field/value pairs to set.

Returns:

Since:

  • 4.0.0



50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
# File 'lib/mongoid/persistable/settable.rb', line 50

def set(setters)
  prepare_atomic_operation do |ops|
    process_atomic_operations(setters) do |field, value|

      field_seq = field.to_s.split('.')
      field = field_seq.shift
      if field_seq.length > 0
        # nested hash path
        old_value = attributes[field]

        # if the old value is not a hash, clobber it
        unless Hash === old_value
          old_value = {}
        end

        # descend into the hash, creating intermediate keys as needed
        cur_value = old_value
        while field_seq.length > 1
          cur_key = field_seq.shift
          # clobber on each level if type is not a hash
          unless Hash === cur_value[cur_key]
            cur_value[cur_key] = {}
          end
          cur_value = cur_value[cur_key]
        end

        # now we are on the leaf level, perform the set
        # and overwrite whatever was on this level before
        cur_value[field_seq.shift] = value

        # and set value to the value of the top level field
        # because this is what we pass to $set
        value = old_value
      end

      process_attribute(field, value)

      unless relations.include?(field.to_s)
        ops[atomic_attribute_name(field)] = attributes[field]
      end
    end
    { "$set" => ops } unless ops.empty?
  end
end