How to get full price for money gem
i am using the money gem and i wanted to know how i can get prices like 23.45, 10.00, 0.32 to show in one field as dollar.cents? I want my cents field to become just Price (money or dollars & cents).
Here is my code:
My model with money gem composed_of:
class Price < ActiveRecord::Base
attr_accessible :name, :date, :cents, :currency
belongs_to :user
validates :name, :presence => true,
:length => { :maximum => 50 }
validates :currency, :presence => true
validates :cents, :presence => true
validates :date, :presence => true
default_scope :order => 'prices.created_at DESC'
composed_of :price,
:class_name => "Money",
:mapping => [%w(cents cents), %w(currency currency_as_string)],
:constructor => Proc.new { |cents, currency| Money.new(cents || 0, currency || Money.default_currency) },
:converter =>开发者_如何学Go Proc.new { |value| value.respond_to?(:to_money) ? value.to_money : raise(ArgumentError, "Can't convert #{value.class} to Money") }
end
The form (i cut out parts for brevity):
<div class="field">
<%= f.label :name %><br />
<%= f.text_field :name %>
</div>
<div class="field">
<%= f.label :date %><br />
<%= f.date_select :date %>
</div>
<div class="field">
<%= f.label :cents %><br />
<%= f.text_field :cents %>
</div>
<><div class="field">
<%= f.label :currency %><br />
<%= f.select(:currency,major_currencies(Money::Currency::TABLE),
{:include_blank => 'Select a Currency'}) %>
</div>
My migration or Price Table:
class CreatePrices < ActiveRecord::Migration
def self.up
create_table :prices do |t|
t.integer :user_id
t.string :name
t.date :date
t.integer :cents, :default => 0
t.string :currency
It seems like i am missing a column or something. It is even suppose to be cents alone? Not sure so i need your help.
Thank you for taking the time.
Just ran into the exact same problem, and if you don't want to change your DB like you did in your chosen answer, simply take a look at the source code of the gem to see if there is anything that you can use:
https://github.com/RubyMoney/money-rails/blob/master/lib/money-rails/helpers/action_view_extension.rb
In this module, you will notice two things:
- A method named humanize_money
- Within that method, a call to the method format on a money object
So, simply call @my_money_object.format, and....bam, you have your money object format to a string WITH the dollars, and the cents amount with a precision of 2.
Example:
@my_money_object = 20.to_money
@my_money_object.format
=> "$20.00"
This is really the correct solution. You specifically said that you "just want the method on getting a full price like $ 45.23." Now if you want to put this formatted string in your DB like that, it is up to you, but I would consider just calling the format method on the money object where needed. I needed to get the formatted price in a controller and obviously didn't have access to the humanize_money method unless I am in a view (without trying to hack out an additional method to do this), so I checked out the source code and found this. Vote up if this helped you in any way.
Well,
In your DB table you hold cents as integers:
t.integer :cents, :default => 0
Try changing that to:
t.decimal :cents, :default => 0
I downloaded the gem and tested a few options. Following the examples from https://github.com/RubyMoney/money you can do:
money = Money.new(1000, "USD")
money.cents #=> 1000
money.dollars #=> 10.0
So in my opinion you should have something like this method in your model Price:
def value
cents / 100.0
end
And use it in the views (or wherever you need value in currency, not cents). When adding a price you are doing it in cents, thus to have a price 12.34 you should set it to 1234 cents. If you want to add price like 12.34, I guess you should parse it in controller (on create/update action) or in the model with filter before_save or something like that. Just multiply it by 100 to save as cents in DB.
EDIT: helper method to add zeros to view.
def with_zeros(price)
array = price.to_s.split('.')
array[1] = array[1].ljust(2,'0')
array.join('.')
end
Alright i was able to figure it out, thanks everyone!
Here is my new code:
Database now is :price instead of :cents -
create_table :prices do |t|
t.integer :user_id
t.string :name
t.date :date
t.integer :price, :default => 0
t.string :currency
form area:
<div class="field">
<%= f.label :price %><br />
<%= f.text_field :price %>
</div>
new composed_of:
composed_of :price,
:class_name => "Money",
:mapping => [%w(price cents), %w(currency currency_as_string)],
:constructor => Proc.new { |cents, currency| Money.new(cents || 0, currency || Money.default_currency) },
:converter => Proc.new { |value| value.respond_to?(:to_money) ? value.to_money : raise(ArgumentError, "Can't conver #{value.class} to Money") }
I just had to make it so the composed_of matches the mapping, database column and form and for some strange reason it starting working entirely. Thanks everyone for the help, i learned a great deal about ruby and the rails.
精彩评论