Rails提前一月到二月有时会失败

时间:2015-10-10 20:40:47

标签: ruby-on-rails date

我正在为订单进行付款安排,客户可以选择当月支付。之后也可以改变它。为此,我使用了advance方法作为日期,它在创建时正常工作,但在更新时失败。这是我的代码:

创建,如果日期是31,如果月份没有第31天,则会正确地更改为月份的最后一天。

months = params[:payment][:months].to_i
pay_day = params[:payment][:pay_day].to_i

today = Date.today
first_date = today.change(months: 1).change(day: pay_day)   
months_between = (today.year * 12 + today.month) - (first_date.year * 12 + first_date.month)

quota = (invoice_total)/months
payment_number = 1

months.times do |i|
    payment = Payment.new(invoice: current_invoice, payment_type: PaymentType.find(params[:payment][:payment_type_id]), payment_number: payment_number, value: quota, max_payment_date: first_date.advance(months: +(months_between+i+1)))
    payment.save
    payment_number = payment_number + 1
end

更新代码,例如,在2月份"无效日期"中失败,但正确更新1月。

pay_day = params[:payment][:pay_day].to_i

@invoice.payments.each do |payment|
    if payment.actual_payment_date.nil?

        reference_month = payment.max_payment_date.change(months: 1).change(day: pay_day)
        months_between = (payment.max_payment_date.year * 12 + payment.max_payment_date.month) - (reference_month.year * 12 + reference_month.month)

        payment.update_attributes(max_payment_date: reference_month.advance(months: +(months_between)))
        payment.save
    end
end 

它基本上是相同的代码,有谁知道为什么在第一部分它正常工作,但不是第二部分?

由于

1 个答案:

答案 0 :(得分:2)

ActiveSupport救援:

def correct_day(day, date = Date.today)
  end_of_month = date.end_of_month.day
  day < end_of_month ? day : end_of_month
end

让我们用[timecop:

进行测试
Timecop.freeze(Date.new(2000, 02)) do
  correct_day(32) # => 29 - 2000 was a leap year.
  correct_day(15) # => 15
end

Timecop.freeze(Date.new(2015, 10, 11)) do
  correct_day(32) # => 31
  correct_day(15) # => 15
end

这是你在模型中实现它的方法:

class Invoice < ActiveRecord::Base
  has_many :payments

  # Creates a payment for each month
  # @param [Integer] months 
  # @param [Ingeger] preferred_day - defaults to the last day of the month
  def split_payments(months = 12, preferred_day = 31)
    (1..months).map do |i|
      payments.create(
          pay_day: calculate_payment_date(created_at + i.months, preferred_day),
          payment_number: i
          # ... More attributes
      )
    end
  end

  def change_payment_date(preferred_day)
    payments.sort_by(:payment_number).map do |payment|
      date = created_at + payment.payment_number.months
      payment.update_attributes(
        pay_day: calculate_payment_date(date, preferred_day) 
      )
    end
  end

  private

    def calculate_payment_date(date, preferred_day)
      end_of_month = date.end_of_month
      pref = date.beginning_of_month + (preferred_day - 1).days
      pref < end_of_month ? pref : end_of_month
    end
end