Module: Mongoid::Persistable::Settable

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

Overview

Defines behavior for $set operations.

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:

  • The field/value pairs to set.

Returns:

  • The document.



48
49
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
# File 'lib/mongoid/persistable/settable.rb', line 48

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