module MoneyRails::ActiveRecord::Monetizable::ClassMethods
Attributes
currency[R]
Public Instance Methods
monetize(*fields)
click to toggle source
# File lib/money-rails/active_record/monetizable.rb, line 22 def monetize(*fields) options = fields.extract_options! fields.each do |field| # Stringify model field name subunit_name = field.to_s if options[:field_currency] || options[:target_name] || options[:model_currency] ActiveSupport::Deprecation.warn("You are using the old " \ "argument keys of the monetize command! Instead use :as, " \ ":with_currency or :with_model_currency") end name = options[:as] || options[:target_name] || nil # Form target name for the money backed ActiveModel field: # if a target name is provided then use it # if there is a "{column.postfix}" suffix then just remove it to create the target name # if none of the previous is the case then use a default suffix if name name = name.to_s # Check if the options[:as] parameter is not the same as subunit_name # which would result in stack overflow if name == subunit_name raise ArgumentError, "monetizable attribute name cannot be the same as options[:as] parameter" end elsif subunit_name =~ /#{MoneyRails::Configuration.amount_column[:postfix]}$/ name = subunit_name.sub(/#{MoneyRails::Configuration.amount_column[:postfix]}$/, "") else raise ArgumentError, "Unable to infer the name of the monetizable attribute for '#{subunit_name}'. " \ "Expected amount column postfix is '#{MoneyRails::Configuration.amount_column[:postfix]}'. " \ "Use :as option to explicitly specify the name or change the amount column postfix in the initializer." end # Optional accessor to be run on an instance to detect currency instance_currency_name = options[:with_model_currency] || options[:model_currency] || MoneyRails::Configuration.currency_column[:column_name] # Infer currency column from name and postfix if !instance_currency_name && MoneyRails::Configuration.currency_column[:postfix].present? instance_currency_name = "#{name}#{MoneyRails::Configuration.currency_column[:postfix]}" end instance_currency_name = instance_currency_name && instance_currency_name.to_s # This attribute allows per column currency values # Overrides row and default currency field_currency_name = options[:with_currency] || options[:field_currency] || nil # Create a reverse mapping of the monetized attributes track_monetized_attribute name, subunit_name # Include numericality validations if needed. # There are two validation options: # # 1. Subunit field validation (e.g. cents should be > 100) # 2. Money field validation (e.g. euros should be > 10) # # All the options which are available for Rails numericality # validation, are also available for both types. # E.g. # monetize :price_in_a_range_cents, allow_nil: true, # subunit_numericality: { # greater_than_or_equal_to: 0, # less_than_or_equal_to: 10000, # }, # numericality: { # greater_than_or_equal_to: 0, # less_than_or_equal_to: 100, # message: "must be greater than zero and less than $100" # } # # To disable validation entirely, use :disable_validation, E.g: # monetize :price_in_a_range_cents, disable_validation: true if (validation_enabled = MoneyRails.include_validations && !options[:disable_validation]) # This is a validation for the subunit if (subunit_numericality = options.fetch(:subunit_numericality, true)) validates subunit_name, { allow_nil: options[:allow_nil], numericality: subunit_numericality } end # Allow only Money objects or Numeric values! if (numericality = options.fetch(:numericality, true)) validates name.to_sym, { allow_nil: options[:allow_nil], 'money_rails/active_model/money' => numericality } end end # Getter for monetized attribute define_method name do |*args| read_monetized name, subunit_name, options, *args end # Setter for monetized attribute define_method "#{name}=" do |value| write_monetized name, subunit_name, value, validation_enabled, instance_currency_name, options end if validation_enabled # Ensure that the before_type_cast value is cleared when setting # the subunit value directly define_method "#{subunit_name}=" do |value| instance_variable_set "@#{name}_money_before_type_cast", nil write_attribute(subunit_name, value) end end # Currency getter define_method "currency_for_#{name}" do currency_for name, instance_currency_name, field_currency_name end attr_reader "#{name}_money_before_type_cast" # Hook to ensure the reset of before_type_cast attr # TODO: think of a better way to avoid this after_save do instance_variable_set "@#{name}_money_before_type_cast", nil end end end
monetized_attributes()
click to toggle source
# File lib/money-rails/active_record/monetizable.rb, line 12 def monetized_attributes monetized_attributes = @monetized_attributes || {} if superclass.respond_to?(:monetized_attributes) monetized_attributes.merge(superclass.monetized_attributes) else monetized_attributes end end
register_currency(currency_name)
click to toggle source
# File lib/money-rails/active_record/monetizable.rb, line 154 def register_currency(currency_name) # Lookup the given currency_name and raise exception if # no currency is found currency_object = Money::Currency.find currency_name raise(ArgumentError, "Can't find #{currency_name} currency code") unless currency_object class_eval do @currency = currency_object class << self attr_reader :currency end end end
Private Instance Methods
track_monetized_attribute(name, value)
click to toggle source
# File lib/money-rails/active_record/monetizable.rb, line 170 def track_monetized_attribute(name, value) @monetized_attributes ||= {}.with_indifferent_access if @monetized_attributes[name].present? raise ArgumentError, "#{self} already has a monetized attribute called '#{name}'" end @monetized_attributes[name] = value end