lib/easy_rails_money/active_record/migration/schema_statements.rb
require 'active_support/core_ext/array/extract_options'
module EasyRailsMoney
module ActiveRecord
module Migration
module SchemaStatements
# Creates one or two columns to represent a Money object in the named table
#
# An integer column for storing Money in its base unit
# eg. cents for a Dollar denomination and a string for storing
# its currency name. Can think of it as a persisted or serialized
# Money object in the database. The integer column is suffixed
# with '_money' to aid in reflection ie. to find all money
# columns. Likewise the currency column is suffixed with '_currency'
# If does not create an individual currency column if a
# common currency column is defined
#
# @param table_name [Symbol|String]
# @param column_names [Array|Symbol|String] List of money columns to add
# @return is not important and can change
#
# @note If we have defined a currency column for a record then only the integer column is defined.
# @see EasyRailsMoney::ActiveRecord::Migration::TableDefinition#money
# @see EasyRailsMoney::ActiveRecord::Migration::Table#money
# @see EasyRailsMoney::ActiveRecord::Migration::TableDefinition#currency
# @see EasyRailsMoney::ActiveRecord::Migration::SchemaStatements#remove_money
def add_money table_name, *args
options = args.extract_options!
Array(args).each do |name|
add_column table_name, "#{name}_money", :integer, options
add_column table_name, "#{name}_currency", :string, options unless has_currency_column?(table_name)
end
end
# Removes the columns which represent the Money object
#
# Removes the two columns added by add_money. The money amount and
# the currency column. If there are no remaining money amount columns
# and a common currency column exists. then it is also removed
#
# @param table_name [Symbol|String]
# @param column_names [Array|Symbol|String] List of money columns to remove
# @return is not important and can change
# @note If we have defined a currency column for a record then currency column is removed only if no other money column are there
#
# @see EasyRailsMoney::ActiveRecord::Migration::Table#remove_money
# @see EasyRailsMoney::ActiveRecord::Migration::SchemaStatements#add_money
# @see EasyRailsMoney::ActiveRecord::Migration::TableDefinition#currency
# @note multiple remove_money calls are not supported in one migration. because at this point the schema is different from the migration defined
def remove_money table_name, *args
options = args.extract_options!
Array(args).each do |name|
remove_column table_name, "#{name}_money"
remove_column table_name, "#{name}_currency"
end
remove_currency table_name, options unless has_money_columns?(table_name)
end
# Removes the common currency column
#
# Usually we create an currency column for each money
# columns. We can have multiple money columns in the same
# record, in which case we can have a single currency
# column. This helper removes that common curremcy column. For
# the existing money column it adds back their currency
# columns as well. It reflects on the database schema by
# looking at the column name. By convention the money amount
# column is prefixed by '_money' and the currency column by '_currency'
#
# @param table_name [Symbol|String]
# @param options [Hash] optional
#
# @see EasyRailsMoney::ActiveRecord::Migration::Table#remove_currency
# @see EasyRailsMoney::ActiveRecord::Migration::SchemaStatements#remove_money
# @see EasyRailsMoney::ActiveRecord::Migration::TableDefinition#currency
def remove_currency table_name, options={}
remove_column table_name, :currency
money_columns(table_name) do |money_column|
add_column table_name, "#{money_column}_currency", :string, options
end
end
protected
def has_currency_column? table_name
connection.schema_cache.clear_table_cache! table_name
connection.schema_cache.columns[table_name].select {|x| x.name == "currency" }.any?
end
def money_columns table_name
# FIXME: see specs tagged
# fixme_need_to_clear_table_cache. for that test needed to
# clear the cache
connection.schema_cache.clear_table_cache! table_name
connection.schema_cache.columns[table_name].select { |col|
col.name =~ /_money/
}.map { |col|
name = col.name.match(/(.+)_money/)[1]
if block_given?
yield name
else
name
end
}
end
def has_money_columns? table_name
money_columns(table_name).any?
end
end
end
end
end