views:

271

answers:

1

I have a model like this:

class Transaction < ActiveRecord::Base
  def amount
    self[:amount].abs
  end

  def transaction_type
    read_attribute(:amount) > 0 ? :credit : :debit
  end

  def transaction_type=(type)
    if type == :credit || type == 'credit'
      self[:amount] = amount.abs
    elsif type == :debit || type == 'debit'
      self[:amount] = amount.abs * -1
    else
      raise ArgumentError.new 'Type must be credit or debit'
    end
  end
end

Because I want my amount column to always be a positive number when rendered. The problem is apparently the view doesn't ever call this method:

<% form_for @transaction do |f| %>
  <%= f.error_messages %>
  <p>
    <%= f.label 'Where?' %><br />
    <%= f.text_field :target %>
  </p>
  <p>
    <%= f.label 'What?' %><br />
    <%= f.text_field :memo %>
  </p>
  <p>
    <%= f.label 'How much?' %><br />
    <%= f.text_field :amount %>
  </p>
  <p>
    <%= f.radio_button :transaction_type, 'debit' %>
    <%= f.label :transaction_type_debit, 'Debit' %>
    <%= f.radio_button :transaction_type, 'credit' %>
    <%= f.label :transaction_type_credit, 'Credit' %>
  </p>
  <p><%= f.submit "Submit" %></p>
<% end %>

Am I doing something wrong? Or is there a better way to do this?

Edit: Added my transaction_type accessor methods, that better explains why I am not storing amount in the DB as only a positive number.

+1  A: 

I had a similar problem a few years ago. Given the time involved, excuse me if I'm wrong.

As far as I recall, form helpers use the *_before_type_cast accessor methods. Consider renaming your method to amount_before_type_cast. There is some more information about the "problem" here.

If, however, you ONLY want the number to be made absolute in views, but still want to use the number in the usual way within the model, this is the wrong approach entirely and you should instead be "sanitizing" your data for use in the view in a different way (i.e. a helper, in the controller, or with an all new non-databased custom attribute on the model).

Peter Cooper