Module: CustomFields::Types::ManyToMany::Target::ClassMethods

Defined in:
lib/custom_fields/types/many_to_many.rb

Instance Method Summary collapse

Instance Method Details

#apply_many_to_many_custom_field(klass, rule) ⇒ Object

Adds a many_to_many relationship between 2 mongoid models

Parameters:

  • klass (Class)

    The class to modify

  • rule (Hash)

    It contains the name of the relation and if it is required or not



29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
# File 'lib/custom_fields/types/many_to_many.rb', line 29

def apply_many_to_many_custom_field(klass, rule)
  # puts "#{klass.inspect}.many_to_many #{rule['name'].inspect}, class_name: #{rule['class_name'].inspect} / #{rule['order_by']}" # DEBUG

  klass.has_and_belongs_to_many rule['name'], class_name: rule['class_name'], inverse_of: rule['inverse_of'],
                                              validate: false, order: rule['order_by'] do
    def filtered(conditions = {}, order_by = nil)
      list = conditions.empty? ? self : where(conditions)

      if order_by
        list.order_by(order_by)
      else
        _naturally_ordered(list, order_by)
      end
    end

    alias_method :ordered, :filtered # backward compatibility + semantic purpose

    def _naturally_ordered(criteria, _order_by = nil)
      # use the natural order given by the initial array (ex: project_ids).
      # Warning: it returns an array and not a criteria object meaning it breaks the chain
      ids = _base.send(_association.name.to_sym)
      criteria.entries.sort { |a, b| ids.index(a.id) <=> ids.index(b.id) }
    end

    def pluck_with_natural_order(*attributes)
      criteria = only([:_id] + [*attributes])
      _naturally_ordered(criteria).map do |entry|
        if attributes.size == 1
          entry.public_send(attributes.first.to_sym)
        else
          attributes.map { |name| entry.public_send(name.to_sym) }
        end
      end
    end
  end

  return unless rule['required']

  klass.validates_collection_size_of rule['name'], minimum: 1, message: :at_least_one_element
end