Module: MoneyRails::ActiveRecord::Monetizable

Extended by:
ActiveSupport::Concern
Defined in:
lib/money-rails/active_record/monetizable.rb

Defined Under Namespace

Modules: ClassMethods Classes: ReadOnlyCurrencyException

Instance Method Summary collapse

Instance Method Details

#currency_for(name, instance_currency_name, field_currency_name) ⇒ Object



277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
# 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) ⇒ Object



181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
# 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) ⇒ Object



221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
# 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