module MoneyRails::ActiveRecord::Monetizable

Public Instance Methods

currency_for(name, instance_currency_name, field_currency_name) click to toggle source
# File lib/money-rails/active_record/monetizable.rb, line 277
def currency_for(name, instance_currency_name, field_currency_name)
  if instance_currency_name.present? && respond_to?(instance_currency_name) &&
      Money::Currency.find(public_send(instance_currency_name))

    Money::Currency.find(public_send(instance_currency_name))
  elsif field_currency_name.respond_to?(:call)
    Money::Currency.find(field_currency_name.call(self))
  elsif field_currency_name
    Money::Currency.find(field_currency_name)
  elsif self.class.respond_to?(:currency)
    self.class.currency
  else
    Money.default_currency
  end
end
read_monetized(name, subunit_name, options = {}, *args) click to toggle source
# File lib/money-rails/active_record/monetizable.rb, line 181
def read_monetized(name, subunit_name, options = {}, *args)
  # Get the cents
  amount = public_send(subunit_name, *args)

  return if amount.nil? && options[:allow_nil]
  # Get the currency object
  attr_currency = public_send("currency_for_#{name}")

  # Get the cached value
  memoized = instance_variable_get("@#{name}")

  # Dont create a new Money instance if the values haven't been changed.
  if memoized && memoized.cents == amount
    if memoized.currency == attr_currency
      result = memoized
    else
      memoized_amount = memoized.amount.to_money(attr_currency)
      write_attribute subunit_name, memoized_amount.cents
      # Cache the value (it may be nil)
      result = instance_variable_set("@#{name}", memoized_amount)
    end
  elsif amount.present?
    # If amount is NOT nil (or empty string) load the amount in a Money
    amount = Money.new(amount, attr_currency)

    # Cache the value (it may be nil)
    result = instance_variable_set("@#{name}", amount)
  end

  if MoneyRails::Configuration.preserve_user_input
    value_before_type_cast = instance_variable_get "@#{name}_money_before_type_cast"
    if errors.has_key?(name.to_sym)
      result.define_singleton_method(:to_s) { value_before_type_cast }
      result.define_singleton_method(:format) { |_| value_before_type_cast }
    end
  end

  result
end
write_monetized(name, subunit_name, value, validation_enabled, instance_currency_name, options) click to toggle source
# File lib/money-rails/active_record/monetizable.rb, line 221
def write_monetized(name, subunit_name, value, validation_enabled, instance_currency_name, options)
  # Keep before_type_cast value as a reference to original input
  instance_variable_set "@#{name}_money_before_type_cast", value

  # Use nil or get a Money object
  if options[:allow_nil] && value.blank?
    money = nil
  else
    if value.is_a?(Money)
      money = value
    else
      begin
        money = value.to_money(public_send("currency_for_#{name}"))
      rescue NoMethodError
        return nil
      rescue Money::Currency::UnknownCurrency, Monetize::ParseError => e
        raise MoneyRails::Error, e.message if MoneyRails.raise_error_on_money_parsing
        return nil
      end
    end
  end

  # Update cents
  if !validation_enabled
    # We haven't defined our own subunit writer, so we can invoke
    # the regular writer, which works with store_accessors
    public_send("#{subunit_name}=", money.try(:cents))
  elsif self.class.respond_to?(:attribute_aliases) &&
      self.class.attribute_aliases.key?(subunit_name)
    # If the attribute is aliased, make sure we write to the original
    # attribute name or an error will be raised.
    # (Note: 'attribute_aliases' doesn't exist in Rails 3.x, so we
    # can't tell if the attribute was aliased.)
    original_name = self.class.attribute_aliases[subunit_name.to_s]
    write_attribute(original_name, money.try(:cents))
  else
    write_attribute(subunit_name, money.try(:cents))
  end

  if money_currency = money.try(:currency)
    # Update currency iso value if there is an instance currency attribute
    if instance_currency_name.present? && respond_to?("#{instance_currency_name}=")
      public_send("#{instance_currency_name}=", money_currency.iso_code)
    else
      current_currency = public_send("currency_for_#{name}")
      if current_currency != money_currency.id
        raise ReadOnlyCurrencyException.new("Can't change readonly currency '#{current_currency}' to '#{money_currency}' for field '#{name}'") if MoneyRails.raise_error_on_money_parsing
        return nil
      end
    end
  end

  # Save and return the new Money object
  instance_variable_set "@#{name}", money
end