5

Here's the code:

class M
  include Mongoid::Document
  field :name
end

params = { name: "foo", age: 20 }
M.create(params)
#=> #<M name: "My Name", age: 20>

Notice that age wasn't defined, yet it was saved.

This is problematic (potentially a source of DoS) because a malicious user can add any parameters in POST and unknown fields with a large string can sneak in. (e.g. name=foo&bogus=#{'x'*1000000})

So far, I couldn't find anything but attr_accessible, but it's not really great for Mongoid as you have to maintain the same field names in both field and attr_accessible all the time, in all models. Not DRY.

I think the attr_accessible API is great for ActiveRecord, because there a. you don't explicitly define fields in the models (DRY) and b. it's guaranteed there's no chance that a nonexistent field gets saved to RDB. But for Mongoid, I think there should be a better solution than attr_accessible.

Note that there's a global config setting allow_dynamic_fields but it's not about mass assignment so it's out of the scope in this discussion, however I think it should actually be a per-model macro and should also take care of mass-assignment.

How are you dealing with this problem?

kenn
  • 3,303
  • 2
  • 29
  • 42

2 Answers2

1

I'm always using attr_accessible in models. I rarely found myself including all fields as accessible. Usually there are always a few fields that shouldn't be accessible for mass assignment. If you often need to include every attribute and you're concerned about duplication:

attr_accessible *fields.keys
Zargony
  • 9,615
  • 3
  • 44
  • 44
0

What I have done to solve this issue, is use a before save callback in my model:

set_callback(:save, :before) do |doc|
    (doc.attributes.keys - fields.keys).each { |f| doc.unset(f) }
end

This way, even if there are extra attributes they get removed before being saved.

HRÓÐÓLFR
  • 5,842
  • 5
  • 32
  • 35