View in Rails doesn't call overridden attribute accessor
-
23-08-2019 - |
Question
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.
Solution
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).