简体   繁体   中英

How to run a callback function on two attributes that depend on each other?

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM