mongoid/mongoid

View on GitHub
lib/mongoid/relations/builders.rb

Summary

Maintainability
A
0 mins
Test Coverage
# encoding: utf-8
require "mongoid/relations/builder"
require "mongoid/relations/nested_builder"
require "mongoid/relations/builders/embedded/in"
require "mongoid/relations/builders/embedded/many"
require "mongoid/relations/builders/embedded/one"
require "mongoid/relations/builders/nested_attributes/one"
require "mongoid/relations/builders/nested_attributes/many"
require "mongoid/relations/builders/referenced/in"
require "mongoid/relations/builders/referenced/many"
require "mongoid/relations/builders/referenced/many_to_many"
require "mongoid/relations/builders/referenced/one"

module Mongoid
  module Relations

    # This module is responsible for defining the build and create methods used
    # in one to one relations.
    #
    # @example Methods that get created.
    #
    #   class Person
    #     include Mongoid::Document
    #     embeds_one :name
    #   end
    #
    #   # The following methods get created:
    #   person.build_name({ :first_name => "Durran" })
    #   person.create_name({ :first_name => "Durran" })
    #
    # @since 2.0.0.rc.1
    module Builders
      extend ActiveSupport::Concern

      private

      # Parse out the attributes and the options from the args passed to a
      # build_ or create_ methods.
      #
      # @example Parse the args.
      #   doc.parse_args(:name => "Joe")
      #
      # @param [ Array ] args The arguments.
      #
      # @return [ Array<Hash> ] The attributes and options.
      #
      # @since 2.3.4
      def parse_args(*args)
        [ args.first || {}, args.size > 1 ? args[1] : {} ]
      end

      module ClassMethods

        # Defines a builder method for an embeds_one relation. This is
        # defined as #build_name.
        #
        # @example
        #   Person.builder("name")
        #
        # @param [ String, Symbol ] name The name of the relation.
        #
        # @return [ Class ] The class being set up.
        #
        # @since 2.0.0.rc.1
        def builder(name, metadata)
          re_define_method("build_#{name}") do |*args|
            attributes, options = parse_args(*args)
            document = Factory.build(metadata.klass, attributes)
            _building do
              child = send("#{name}=", document)
              child.run_callbacks(:build)
              child
            end
          end
          self
        end

        # Defines a creator method for an embeds_one relation. This is
        # defined as #create_name. After the object is built it will
        # immediately save.
        #
        # @example
        #   Person.creator("name")
        #
        # @param [ String, Symbol ] name The name of the relation.
        #
        # @return [ Class ] The class being set up.
        #
        # @since 2.0.0.rc.1
        def creator(name, metadata)
          re_define_method("create_#{name}") do |*args|
            attributes, options = parse_args(*args)
            document = Factory.build(metadata.klass, attributes)
            doc = _assigning do
              send("#{name}=", document)
            end
            doc.save
            save if new_record? && metadata.stores_foreign_key?
            doc
          end
          self
        end
      end
    end
  end
end