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.
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:
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.