views:

227

answers:

2

Hi,

I am wondering how I could create a custom data type to use within the rake migration file. Example: if you would be creating a model, inside the migration file you can add columns. It could look like this:

  def self.up
    create_table :products do |t|
      t.column :name, :string
      t.timestamps
    end
  end

I would like to know how to create something like this:

t.column :name, :my_custom_data_type

The reason for this to create for example a "currency" type, which is nothing more than a decimal with a precision of 8 and a scale of 2. Since I use only MySQL, the solution for this database is sufficient enough.

Thank you for your feedback and comments!

A: 

I recommend that you use integers to store your currency amounts (and measure in cents). If you do want to create a decimal to store your currencies and use the fixed precision and scale, try:

t.decimal :amount, :precision => 8, :scale => 2
Kevin Sylvestre
-1: You've missed the point of the question. Shyam is looking for a way to DRY up his creation of decimal columns, not how to define them the long way.
EmFi
Indeed. Even though if I would use two fields that contains integers, as in one for amount and a separate for amount, I still would like to use a short hand.
Shyam
Quoting from my own question: "The reason for this to create for example a "currency" type, which is nothing more than a decimal with a precision of 8 and a scale of 2."
Shyam
Why don't you just store $344.12 as 34412 in an integer field? This is a fairly standard way of storing currency amounts in rails (as used by ActiveMerchant and a variety of other gems).
Kevin Sylvestre
how would I convert the 34412 into $334.12? The integer solution sounds like a good idea, but i need to implement it too!
Shyam
Try one of the currency gems such as http://github.com/collectiveidea/money or http://money.rubyforge.org/.
Kevin Sylvestre
`number_to_currency 33412 / 100.0`
mikezter
+5  A: 

What you're looking to do is define a new column creation method that provides the options to create your custom type. Which is essentially done by adding a method that behaves like t.integer ... in migrations. The trick is figuring out where to add that code.

Some where in your initializers directory place this snippet of code:

module ActiveRecord::ConnectionAdapters
  class TableDefinition
    def currency (*args)
      options = args.extract_options!
      column_names = args
      options[:precision] ||= 8
      options[:scale] ||= 2
      column_names.each { |name| column(name, 'decimal', options) }
    end                                                                     
  end
end

Now you can use the currency method do define a currency column any time you need it.

Example:

def self.up
  create_table :products do |t|
    t.currency :cost
    t.timestamps
  end
end

To add a currency column to an existing table:

def self.up
  change_table :products do |t|
    t.currency :sell_price
  end
end   

Caveat: I haven't time to test it, so there's no guarantees. If it doesn't work, it should at least put you on the right track.

EmFi
I am going to test this right away. Thank you for the effort and your help!
Shyam