Uploaded image for project: 'Mongoid'
  1. Mongoid
  2. MONGOID-2703

Validates fields and embedded documents that were not changed

    XMLWordPrintable

    Details

    • Type: Task
    • Status: Closed
    • Resolution: Done
    • Affects Version/s: None
    • Fix Version/s: 3.0.20
    • Component/s: None
    • Labels:

      Description

      According to documentation Mongoid should not validate fields that were not changed.

      > Mongoid behaves slightly different to Active Record when using #valid? on already persisted data. Active Record's #valid? will run all validations whereas Mongoid's #valid? will only run validations on fields where data has changed as an optimization.
      > (http://mongoid.org/en/mongoid/docs/validation.html)

      Here's a script that proves otherwise:

      #!/usr/bin/env ruby
       
      require "mongoid"
       
      Mongoid.configure do |config|
        config.connect_to "mongoid_test"
      end
       
      class A
        include Mongoid::Document
       
        field :name, type: String
        validates :name, presence: true
      end
       
      A.delete_all
       
      a = A.new
      a.save! validate: false
       
      a = A.first
      puts "Changed: #{a.changed?}, #{a.name_changed?}"
      puts "Valid: #{a.valid?}"
       
      a.errors.full_messages.each do |m|
        puts m
      end
      

      Output:
      > Changed: false, false
      > Valid: false
      > Name can't be blank

      But frankly, I don't care about ordinary fields. I was expecting Mongoid to skip validation of embedded documents if they were not changed. This sounds like an obvious optimization and in various forms has been mentioned in different issues (like MONGOID-723). I have a document with 1.5k embedded documents. Running valid? on that parent document takes 50s on my production server. My users can't do anything on that document in my webapp.

      If on the other hand I were to pass validate: false to the embeds_many definition, none of the newly added children would be validated.

      Here's another example script, this time with embedded children:

      #!/usr/bin/env ruby
       
      require "mongoid"
       
      Mongoid.configure do |config|
        config.connect_to "mongoid_test"
      end
       
      class B
        include Mongoid::Document
        embedded_in :a
       
        field :name, type: String
        validates :name, presence: true
      end
       
      class A
        include Mongoid::Document
       
        embeds_many :b
      end
       
      A.delete_all
       
      a = A.new
      5.times {a.b.build}
      a.save! validate: false
       
      a = A.first
      puts "Changed: #{a.changed?}"
      puts "B size: #{a.b.size}"
      puts "Valid: #{a.valid?}"
       
      a.errors.full_messages.each do |m|
        puts m
      end
      

      Output:
      > Changed: false
      > B size: 5
      > Valid: false
      > B is invalid

        Attachments

          Activity

            People

            • Votes:
              0 Vote for this issue
              Watchers:
              0 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved: