module Mongoid::Denormalize

Constants

VERSION

Public Class Methods

add_hook_to_child(child_class, fields, options) click to toggle source

Add hook to child class to denormalize fields when parent relation is changed

# File lib/mongoid-denormalize.rb, line 54
def self.add_hook_to_child(child_class, fields, options)
  from = options[:from].to_s

  child_class.send(options[:child_callback] || 'before_save') do
    if send("#{from}_id_changed?")
      fields.each do |field|
        send("#{field[:as]}=", send(from)&.send(field[:name]))
      end
    end
  end
end
add_hook_to_parent(child_class, fields, options) click to toggle source

Add hook to parent class to denormalize fields when parent object is updated

# File lib/mongoid-denormalize.rb, line 67
def self.add_hook_to_parent(child_class, fields, options)
  from = options[:from].to_s

  parent = parent_class(child_class, from)

  relation = parent.relations[child_class.relations[from].inverse_of.to_s] ||
             parent.relations[child_class.model_name.plural] ||
             parent.relations[child_class.model_name.singular]

  unless relation
    raise "Option :inverse_of is needed for 'belongs_to :#{from}' into #{child_class}."
  end

  parent.after_update do
    attributes = {}
    fields.each do |field|
      attributes[field[:as]] = send(field[:name]) if send("#{field[:name]}_changed?")
    end
    next if attributes.blank?

    case relation.relation.to_s
    when 'Mongoid::Relations::Referenced::One',
         'Mongoid::Association::Referenced::HasOne::Proxy'
      if (document = send(relation.name))
        document.collection.update_one({_id: document._id}, {'$set' => attributes})
      end
    when 'Mongoid::Relations::Referenced::Many',
         'Mongoid::Association::Referenced::HasMany::Proxy'
      send(relation.name).update_all('$set' => attributes)
    else
      raise "Relation type unsupported: #{relation.relation}"
    end
  end
end
field_type(klass, field) click to toggle source

Retreive the type of a field from the given class

# File lib/mongoid-denormalize.rb, line 109
def self.field_type(klass, field)
  klass.fields[field.to_s].options[:type]
end
get_fields_with_names(child_class, fields, options) click to toggle source

Check options and return name for each field

# File lib/mongoid-denormalize.rb, line 29
def self.get_fields_with_names(child_class, fields, options)
  parent = parent_class(child_class, options[:from].to_s)

  if options.include?(:as)
    options[:as] = [options[:as]] unless options[:as].is_a?(Array)

    unless fields.size == options[:as].size
      raise ArgumentError, 'When option :as is used you must pass a name for each field.'
    end

    return fields.map.with_index do |field, index|
      {name: field, as: options[:as][index], type: field_type(parent, field)}
    end
  elsif options.include?(:prefix)
    return fields.map do |field|
      {name: field, as: "#{options[:prefix]}_#{field}", type: field_type(parent, field)}
    end
  end

  fields.map do |field|
    {name: field, as: "#{options[:from]}_#{field}", type: field_type(parent, field)}
  end
end
included(base) click to toggle source
# File lib/mongoid-denormalize.rb, line 5
def self.included(base)
  base.extend ClassMethods
end
parent_class(child_class, from) click to toggle source

Retrieve parent class

# File lib/mongoid-denormalize.rb, line 103
def self.parent_class(child_class, from)
  (child_class.relations[from].class_name || child_class.relations[from].name.capitalize)
    .constantize
end