Validates fields and embedded documents that were not changed

XMLWordPrintableJSON

    • Type: Task
    • Resolution: Done
    • 3.0.20
    • Affects Version/s: None
    • Component/s: None
    • None
    • None
    • None
    • None
    • None
    • None
    • None

      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

            Assignee:
            Unassigned
            Reporter:
            Adam Wróbel
            Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

              Created:
              Updated:
              Resolved: