class NoBrainer::Document::Association::BelongsTo::Metadata

Constants

VALID_OPTIONS

Public Instance Methods

base_criteria(target_class = nil) click to toggle source
# File lib/no_brainer/document/association/belongs_to.rb, line 54
def base_criteria(target_class = nil)
  model = target_model(target_class)

  model ? model.without_ordering : nil
end
cast_attr(key, value, target_class = nil) click to toggle source
# File lib/no_brainer/document/association/belongs_to.rb, line 109
def cast_attr(key, value, target_class = nil)
  case value
  when target_model(target_class)
    [foreign_key, value.__send__(primary_key)]
  when nil
    if options[:polymorphic]
      [[foreign_type, foreign_key], nil]
    else
      [foreign_key, nil]
    end
  else
    raise NoBrainer::Error::InvalidType.new(
      model: owner_model, attr_name: key, type: target_model, value: value
    )
  end
end
eager_load_owner_key() click to toggle source
# File lib/no_brainer/document/association/belongs_to.rb, line 126
def eager_load_owner_key;  foreign_key; end
eager_load_owner_type() click to toggle source
# File lib/no_brainer/document/association/belongs_to.rb, line 127
def eager_load_owner_type; foreign_type; end
eager_load_target_key() click to toggle source
# File lib/no_brainer/document/association/belongs_to.rb, line 128
def eager_load_target_key; primary_key; end
foreign_key() click to toggle source
# File lib/no_brainer/document/association/belongs_to.rb, line 13
def foreign_key
  options[:foreign_key].try(:to_sym) || :"#{target_name}_#{primary_key}"
end
foreign_type() click to toggle source
# File lib/no_brainer/document/association/belongs_to.rb, line 17
def foreign_type
  return nil unless options[:polymorphic]

  options[:foreign_type].try(:to_sym) || (:"#{target_name}_type")
end
hook() click to toggle source
# File lib/no_brainer/document/association/belongs_to.rb, line 60
def hook
  super

  # TODO set the type of the foreign key to be the same as the target's primary key
  if owner_model.association_metadata.values.any? { |assoc|
      assoc.is_a?(self.class) && assoc != self && assoc.foreign_key == foreign_key }
    raise "Cannot declare `#{target_name}' in #{owner_model}: the foreign_key `#{foreign_key}' is already used"
  end

  if options[:polymorphic] && options[:class_name]
    raise 'You cannot set class_name on a polymorphic belongs_to'
  end

  if options[:polymorphic]
    if options[:uniq] || options[:unique]
      owner_model.field(foreign_type, uniq: { scope: foreign_key })
      owner_model.index([foreign_type, foreign_key])
    else
      owner_model.field(foreign_type)
    end
  end

  owner_model.field(foreign_key, store_as: options[:foreign_key_store_as], index: options[:index])

  unless options[:validates] == false
    owner_model.validates(target_name, options[:validates]) if options[:validates]

    uniq = options[:uniq] || options[:unique]
    if uniq
      owner_model.validates(foreign_key, :uniqueness => uniq)
    end

    if options[:required]
      owner_model.validates(target_name, :presence => options[:required])
    else
      # Always validate the foreign_key if not nil.
      owner_model.validates_each(foreign_key) do |doc, attr, value|
        if !value.nil? && value != doc.pk_value && doc.read_attribute_for_validation(target_name).nil?
          doc.errors.add(attr, :invalid_foreign_key, :target_model => target_model, :primary_key => primary_key)
        end
      end
    end
  end

  delegate("#{foreign_key}=", :assign_foreign_key, :call_super => true)
  delegate("#{target_name}_changed?", "#{foreign_key}_changed?", :to => :self)
  add_callback_for(:after_validation)
end
primary_key() click to toggle source
# File lib/no_brainer/document/association/belongs_to.rb, line 23
def primary_key
  # We default the primary_key to `:id' and not `target_model.pk_name',
  # because we don't want to require the target_model to be already loaded.
  # (We want the ability to load models in any order).
  # Using target_model.pk_name and allowing lazy loading of models is
  # difficult due to the inexistant API to remove validations if the
  # foreign_key name was to be changed as the pk_name gets renamed.
  return options[:primary_key].to_sym if options[:primary_key]

  NoBrainer::Document::PrimaryKey::DEFAULT_PK_NAME.tap do |default_pk_name|
    # We'll try to give a warning when we see a different target pk name (best effort).
    real_pk_name = target_model.pk_name rescue nil
    if real_pk_name && real_pk_name != default_pk_name
      raise "Please specify the primary_key name on the following belongs_to association as such:\n" +
            "  belongs_to :#{target_name}, :primary_key => :#{real_pk_name}"
    end
  end
end
target_model(target_class = nil) click to toggle source
# File lib/no_brainer/document/association/belongs_to.rb, line 42
def target_model(target_class = nil)
  return if options[:polymorphic] && target_class.nil?

  model_name = if options[:polymorphic]
                 target_class
               else
                 options[:class_name] || target_name.to_s.camelize
               end

  get_model_by_name(model_name)
end