In my Rails app I have an Invoice
model with the attributes date
and due_date
.
For reasons of simplicity I don't want the user to manually enter the due_date
but rather simply enter the number of days that should be added to the date
.
This is why I set up a virtual attribute days_allowed
.
class Invoice < ActiveRecord::Base
belongs_to :user
before_save :save_date
attr_accessor :days_allowed
def days_allowed # attribute reader (I need that too!)
(due_date - date).to_i
end
def save_date
self.due_date = date + days_allowed.days
end
end
However, when a user picks a date in the form and enters a number of days, eg 10
, I get wrong results because the save_date
callback refers to the days_allowed
method rather than the attribute of the same name.
The key problem seems to be that I am using the callback on two different attributes that depend on each other ( date
and days_allowed
).
Can anybody tell me how to solve this puzzle?
Thanks for any help.
How about this approach (no before_save
is necessary):
class Invoice < ActiveRecord::Base
belongs_to :user
def days_allowed
(due_date - date).to_i
end
def days_allowed=(days)
self.due_date = date + days
end
end
EDIT Not supposed to work with mass assignment when both date
and days_allowed
are present unless date
always goes first.
I think you need to store all three fields, just not provide any form attributes for editing the calculated one.
While your use-case at it is might seem like this is a violation of 'don't repeat yourself', I think this is an instance of coincidental duplication. Let me explain:
Consider your next problem - you are going to start having due dates on weekends, holidays, etc. For exactly that reason I wrote the business_time gem:
https://github.com/bokmann/business_time
so in your solution where you add 10 days, you can now add 10 business days. The exact due date can now fluctuate across weekends, 3-day weekends created by holidays, etc. And if you have to deal with snow days, like most of the East Coast of the US has had to lately, you can just add tham as a holiday and recalculate. The number of business days is still 10, but the due date has changed. The number of business days was a critical piece of data to save, not a piece of data to calculate. The due data needs to be saved, because its a piece of information calculated in a context that you'll want to save for querying rather than try to recalculate every time.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.