opensoul.org

acts_as_money

At Collective Idea, we often try to take pieces of code that we use often and extract them into plugins. We’re trying to get better about making them available, so, here we go:

acts_as_money is a fairly trivial plugin that has proved to be very useful. It just makes it a little easier to work with the money gem.

class Product < ActiveRecord::Base
  money :price
end

This assumes that there are 2 columns in the database, cents (integer) and currency (string). These fields can be changed by setting the :cents and :currency options. To use the default currency, you can simple set :currency option to false and not have a currency field.

class Room < ActiveRecord::Base
  money :rate, :cents => :rate_in_cents, :currency => :rate_currency
  money :discount, :cents => :discount_in_cents, :currency => false
end

acts_as_money also incorporates a patch to composed_of that I submitted to core that allows you to pass a String, Fixnum, Float or Money object as a parameter to the setter, and it will call #to_money to convert it to a Money object. This makes it convenient for using money fields in forms.

r = Room.new :rate => "100.00"
r.rate                            # returns &lt;Money:0x249ef9c @currency="USD", @cents=10000&gt;

Installation

script/plugin install git://github.com/collectiveidea/acts_as_money.git

Hope you find this useful. I know I’ve been using it in any app that handles money, and it’s been a time saver. Allowing me to use a composed_of field in forms has been extremely helpful.

plugin and rails November 13, 2006

23 Comments

  1. Haig Didizian Haig Didizian January 9, 2007

    Brandon, can you tell us how you’ve licensed this plugin? I can’t seem to find anything in the code about it… Thanks!!

  2. Brandon Keepers Brandon Keepers January 9, 2007

    Haig,

    MIT. I’ll add it to the code.

  3. John Ward John Ward March 16, 2007

    I think it would be a good idea to package the acts_as_money without the composed_of patch.

    Had you considered that?

    This is not a reflection on the quality or otherwise, just that it would appear separate from the money code.

  4. Brandon Brandon March 16, 2007

    John,

    When I initially released it, acts_as_money actually didn’t use the aggregations patch. But the code was doing some ugly string eval stuff. It was only a couple lines, but ugly none-the-less. I added the aggregations patch to demonstrate its usefulness (no one cared).

    I ended up packaging the patch as a plugin, so I could remove it from acts_as_money, but I’m guessing people would find it more annoying to have to install 2 plugins.
    Unless it’s getting in the way, I think I’m going to leave it as is. Got any good reasons to remove it?

  5. John Ward John Ward March 17, 2007

    Brandon,
    Thanks for the reply.

    The reasons I was considering were as its been posted as a patch it will eventually end up in core rails.

    John

  6. LBo LBo May 6, 2007

    Hi Brandon,

    My users have to fill in a price with two seperate input fields. One for a full amount and one for cents. Together it makes the whole price.

    What would be the best way to take care of the separate formvalues in combination with this plugin?

  7. Brandon Brandon May 7, 2007

    LBo,

    There’s not exactly a way to do it with the acts_as_money plugin, but if you look at the source for the plugin, it’s very trivial. Mainly, it makes use of a patch to composed_of, which I have also packaged as a plugin. In your situation, I would just install the composed_of plugin patch, then do something like the following in your model:

    composed_of :price, :class_name =&gt; 'Money',
        :mapping =&gt; [%w(cents cents), %w(currency currency)] do |hash|
      Money.new("#{hash[:dollars]}.#{hash[:cents]}", hash[:currency])
    end
    

    And then in your views:

    text_field_tag 'mymodel[price][dollars]'
    text_field_tag 'mymodel[price][cents]'
    
  8. JM JM January 15, 2008

    I haven’t tried this myself… does this plugin work with Rails 2.0?

  9. Srgt PPD Srgt PPD February 20, 2008

    How do you remove the dollar sign from the format method? I tried to delete it, but nothing happend. Search within the code of the plugin but couldn’t find any more “$” signs.

  10. Brandon Brandon February 20, 2008

    Srgt PPD,

    The “$” is coming from the money gem. If you want the amount without it, you can just call #to_s on the money object.

  11. nathaniel nathaniel March 3, 2008

    I am having a hell of time with acts_as_money and rails 2.0.2. Everytime I edit a record and click save, whatever price is in my price field gets two extra zeros. I am forced to trim two zeros off of every price field everytime I open a record for editing, even if all I wanted to do was adjust a different field.

    I have no idea why this is happening. Has anyone had this sort of issue happen to them?

  12. Alexander Mikhailian Alexander Mikhailian January 4, 2009

    I just tried your acts_as_money plugin with rails 2.2.2 and rails 2.1.0 and I get in both cases the following exception:

    Unknown key(s): converter

    with the App Stacktrace

    vendor/rails/activesupport/lib/active_support/core_ext/hash/keys.rb:47:in `assert_valid_keys'
    vendor/plugins/composed_of_conversion/lib/aggregations.rb:136:in `composed_of'
    vendor/plugins/acts_as_money/lib/acts_as_money.rb:21:in `money'
    app/models/transfer.rb:7
    app/controllers/clients_controller.rb:18:in `show'
    
  13. Brandon Brandon January 4, 2009

    Alexander,

    The plugin should be compatible with edge and 2.2. Use the rails-2.1 tag for 2.1 and prior.

  14. Alexander Mikhailian Alexander Mikhailian January 4, 2009

    Mea culpa, I just noticed that I did not test it with 2.1.0. Forgot to unfreeze.

    Anyway, it is not working with 2.2.2 (the one that installs by default today with gem install rails).

    P.S. Thanks for the lib, anyway. It is a nice hack. If only the money gem was not sucking so much…

  15. Brandon Brandon January 4, 2009

    Alexander,

    Check out our fork of the money gem, which incorporates the functionality of this plugin. Install the Rails 2.2 and RSpec gems and run rake spec. The tests pass for me. Let me know if they don’t pass for you.

  16. Alexander Mikhailian Alexander Mikhailian February 4, 2009

    Aha, it works. 60 seconds running and I have not issues with your fork of the money plugin, yet ;-)

    Actually, the 2.1.0 version did not work for me on update of the money fields in the views, but this is already history, I suppose

  17. Rob Bazinet Rob Bazinet May 6, 2009

    Brandon,

    I am getting the same error as Alexander above, where I get the message:

    Unknown key(s): converter

    I have Rails 2.1.2 (error originally started with Rails 2.1.0, thought I might upgrade to 2.1.2) and the Rails-2.1 tag of acts_as_money. I am using the “standard” money gem not your forked version.

    Any advice? Any clue to what is happening would be great.

    Thank you.

  18. Brandon Brandon May 7, 2009

    Make sure you have the rails-2.1 tag checked out (and that you restarted your server after switching to it). It doesn’t use the :converter option, which was added in Rails 2.2.

  19. Rob Bazinet Rob Bazinet May 7, 2009

    No, I am getting an error when executing this line:

    a.price.format(:no_cents)

    Without the format(:no_cents) it works for but with the format I get the error:

    undefined method `has_key?’ for [:no_cents]:Array

    Is this not an option people are using? I have the 2.1 tag and it works fine w/o the format but I need to not show anything past the decimal point.

    Thanks.

  20. stephen stephen March 17, 2010

    trying to get acts_as_money working with little luck. I have tried both the standard money gem, v2.2.0 and collectiveidea’s money gem and neither seem to function with acts_as_money. Quick rundown of the problem…

    1. Install money gem and acts_as_money
    2. Create a new project and create a basic scaffold
    3. Specify one object in the model as money
    4. Restart server.
    5. New columns in DB for _as_cents
    6. Try to create new records using simple forms.

    At this point the records are created and data is fed to the database for all fields EXCEPT the object which has been specified as being money. When I check the database both the original value is null and the value_as_cents is 0. I must be doing something stupid but hey, we all do sometimes. Iam running Rails 2.3.4. Thanks,

  21. Brandon Keepers Brandon Keepers March 17, 2010

    Hi stephen,

    I have moved acts_as_money into the collectiveidea fork of the money gem. You shouldn’t need to install the plugin separately now. If you install our fork of the money gem as a plugin, it should Just Work™. If you install it as a gem, you’ll need to require ‘money/rails’.

  22. stephen stephen March 17, 2010

    hmmm… I removed acts_as_money and added the require ‘money/rails’ (i had require ‘money’) before. I also have config.gem ‘collectiveidea-money’ listed in the environment.rb. When I do a rake gems I see collectiveidea-money listed with an “R” status. In my model I have… money :secured, :cents => :secured_in_cents, :currency => “USD” It still isn’t working though so I must have the syntax wrong. The only difference now is that both the value of “secured” and “secured_in_cents” are both null now where before the value_as_cents was being set to 0.

  23. Michael Gatto Michael Gatto April 26, 2010

    Hi Brandon,

    I’m using the rails plugin 2.1 branch. It deploys fine but when I test the app I get this error: NoMethodError (undefined method `price=‘. It seems as if the plugin is not altering activerecord’s behavior. I installed manually since my dev machine is Windows without git.

My name is Brandon Keepers. I like to build things, usually in Ruby or JavaScript. I work at GitHub and live in Holland, MI.

Popular Posts