Search code examples
arraysruby-on-rails-4mongoidmongoid4

Mongoid 4 update array attribute in a document


What is the mistake in this code for not be able to update an array within a document?

Model

class Foo
  include Mongoid::Document
  include Mongoid::Timestamps::Created

  field :myarray, type: Array

end

Controller

def add_item
        @foo = Foo.find_by(uuid: params[:uuid])
        unless @foo.nil?
            unless @foo.has_attribute? :myarray
                @foo[:myarray] = Array.new
            end
            @foo[:myarray] << params[:item]
            @foo.save
        end
end

I am using Rails 4 with MongoId 4 and if I do p @foo before @foo.save I can see @foo correctly changed but for any reason the update is not persisted.


Solution

  • When you say this:

    @foo[:myarray] << params[:item]
    

    You're modifying the myarray array in-place so Mongoid probably won't recognize that it has changed. Then when you say @foo.save, Mongoid will look at @foo to see what has changed; but the array reference in @foo[:myarray] won't change so Mongoid will decide that nothing has changed and @foo.save won't do anything.

    If you force a new array reference to be created by saying:

    @foo[:myarray] += [ params[:item] ] # Or anything else that creates a whole new array
    

    then Mongoid will notice that @foo[:myarray] has changed and @foo.save will send the change down to MongoDB via $set operation on the underlying document.

    This looks like the Mongoid version of this ActiveRecord problem with PostgreSQL array columns:

    New data not persisting to Rails array column on Postgres

    The rule of thumb is "don't edit mutable values in-place, create whole new values instead: copy, edit, replace". That way you don't have to worry about manually managing the "is dirty" flags.