require 'mongoid' # require 'mongoid/document' module Mongoid #:nodoc: module Validations #:nodoc: class AssociatedValidator < ActiveModel::EachValidator def validate_each(document, attribute, value) values = value.is_a?(Array) ? value : [ value ] return if values.collect { |doc| doc.nil? || doc.valid? }.all? document.errors.add(attribute, :invalid, options.merge(:value => value)) # was causing "can't modify frozen hash" end end end end # Mongoid causes the following warning "Collection#group no longer take a list of paramters. This usage is deprecated.Check out the new API at http://api.mongodb.org/ruby/current/Mongo/Collection.html#group-instance_method" # it's already corrected in the mongoid master branch so waiting for the new gem to remove this patch module Mongoid #:nodoc: module Contexts #:nodoc: class Mongo def aggregate klass.collection.group( :key => options[:fields], :cond => selector, :initial => { :count => 0 }, :reduce => Javascript.aggregate ) end def group klass.collection.group( :key => options[:fields], :cond => selector, :initial => { :group => [] }, :reduce => Javascript.group ).collect do |docs| docs["group"] = docs["group"].collect do |attrs| Mongoid::Factory.build(klass, attrs) end docs end end def grouped(start, field, reduce) collection = klass.collection.group( :cond => selector, :initial => { start => "start" }, :reduce => reduce.gsub("[field]", field) ) collection.empty? ? nil : collection.first[start.to_s] end end end end # # http://github.com/emk/mongoid/blob/503e346b1b7b250d682a12332ad9d5872f1575e6/lib/mongoid/atomicity.rb # module Mongoid #:nodoc: # module Atomicity #:nodoc: # extend ActiveSupport::Concern # # def _updates # processed = {} # # _children.inject({ "$set" => _sets, "$pushAll" => {}, :other => {} }) do |updates, child| # changes = child._sets # updates["$set"].update(changes) # unless changes.empty? # processed[child._conficting_modification_key] = true # end # # # MongoDB does not allow "conflicting modifications" to be # # performed in a single operation. Conflicting modifications are # # detected by the 'haveConflictingMod' function in MongoDB. # # Examination of the code suggests that two modifications (a $set # # and a $pushAll, for example) conflict if (1) the key paths being # # modified are equal or (2) one key path is a prefix of the other. # # So a $set of 'addresses.0.street' will conflict with a $pushAll # # to 'addresses', and we will need to split our update into two # # pieces. We do not, however, attempt to match MongoDB's logic # # exactly. Instead, we assume that two updates conflict if the # # first component of the two key paths matches. # if processed.has_key?(child._conficting_modification_key) # target = :other # else # target = "$pushAll" # end # # child._pushes.each do |attr, val| # if updates[target].has_key?(attr) # updates[target][attr] << val # else # updates[target].update({attr => [val]}) # end # end # updates # end.delete_if do |key, value| # value.empty? # end # end # # protected # # Get the key used to check for conflicting modifications. For now, we # # just use the first component of _path, and discard the first period # # and everything that follows. # def _conficting_modification_key # _path.sub(/\..*/, '') # end # end # end # ## various patches # module Mongoid #:nodoc: # module Document # # def update_child_with_noname(child, clear = false) # name = child.association_name # return if name.blank? # fix a weird bug with mongoid-acts-as-tree # update_child_without_noname(child, clear) # end # # alias_method_chain :update_child, :noname # # # module ClassMethods # # # # def instantiate(attrs = nil, allocating = false) # used by carrierwave to back up the original file # # document = super # # document.send(:run_callbacks, :initialize) do # # document # # end # # end # # # # end # # end # end